debian-mirror-gitlab/lib/gitlab/instrumentation/redis_base.rb

186 lines
6.3 KiB
Ruby
Raw Normal View History

2020-06-23 00:09:42 +05:30
# frozen_string_literal: true
require 'redis'
module Gitlab
module Instrumentation
class RedisBase
class << self
include ::Gitlab::Utils::StrongMemoize
include ::Gitlab::Instrumentation::RedisPayload
# TODO: To be used by https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/395
# as a 'label' alias.
def storage_key
self.name.demodulize.underscore
end
def add_duration(duration)
::RequestStore[call_duration_key] ||= 0
::RequestStore[call_duration_key] += duration
end
2022-10-11 01:57:18 +05:30
def add_call_details(duration, commands)
2020-06-23 00:09:42 +05:30
return unless Gitlab::PerformanceBar.enabled_for_request?
detail_store << {
2022-10-11 01:57:18 +05:30
commands: commands,
2020-06-23 00:09:42 +05:30
duration: duration,
backtrace: ::Gitlab::BacktraceCleaner.clean_backtrace(caller)
}
end
2022-10-11 01:57:18 +05:30
def increment_request_count(amount = 1)
2020-06-23 00:09:42 +05:30
::RequestStore[request_count_key] ||= 0
2022-10-11 01:57:18 +05:30
::RequestStore[request_count_key] += amount
2020-06-23 00:09:42 +05:30
end
def increment_read_bytes(num_bytes)
::RequestStore[read_bytes_key] ||= 0
::RequestStore[read_bytes_key] += num_bytes
end
def increment_write_bytes(num_bytes)
::RequestStore[write_bytes_key] ||= 0
::RequestStore[write_bytes_key] += num_bytes
end
2023-03-04 22:38:38 +05:30
def increment_cross_slot_request_count(amount = 1)
::RequestStore[cross_slots_key] ||= 0
::RequestStore[cross_slots_key] += amount
end
def increment_allowed_cross_slot_request_count(amount = 1)
::RequestStore[allowed_cross_slots_key] ||= 0
::RequestStore[allowed_cross_slots_key] += amount
end
2020-06-23 00:09:42 +05:30
def get_request_count
::RequestStore[request_count_key] || 0
end
def read_bytes
::RequestStore[read_bytes_key] || 0
end
def write_bytes
::RequestStore[write_bytes_key] || 0
end
def detail_store
::RequestStore[call_details_key] ||= []
end
2023-03-04 22:38:38 +05:30
def get_cross_slot_request_count
::RequestStore[cross_slots_key] || 0
end
def get_allowed_cross_slot_request_count
::RequestStore[allowed_cross_slots_key] || 0
end
2020-06-23 00:09:42 +05:30
def query_time
query_time = ::RequestStore[call_duration_key] || 0
query_time.round(::Gitlab::InstrumentationHelper::DURATION_PRECISION)
end
2023-01-13 00:05:48 +05:30
def redis_cluster_validate!(commands)
2023-03-04 22:38:38 +05:30
return true unless @redis_cluster_validation
result = ::Gitlab::Instrumentation::RedisClusterValidator.validate(commands)
return true if result.nil?
if !result[:valid] && !result[:allowed] && (Rails.env.development? || Rails.env.test?)
raise RedisClusterValidator::CrossSlotError, "Redis command #{result[:command_name]} arguments hash to different slots. See https://docs.gitlab.com/ee/development/redis.html#multi-key-commands"
end
increment_allowed_cross_slot_request_count if result[:allowed]
result[:valid]
2020-07-28 23:09:34 +05:30
end
def enable_redis_cluster_validation
@redis_cluster_validation = true
self
end
2022-10-11 01:57:18 +05:30
def instance_count_request(amount = 1)
2020-07-28 23:09:34 +05:30
@request_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_requests_total, 'Client side Redis request count, per Redis server')
2022-10-11 01:57:18 +05:30
@request_counter.increment({ storage: storage_key }, amount)
2020-07-28 23:09:34 +05:30
end
def instance_count_exception(ex)
# This metric is meant to give a client side view of how the Redis
# server is doing. Redis itself does not expose error counts. This
# metric can be used for Redis alerting and service health monitoring.
@exception_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_exceptions_total, 'Client side Redis exception count, per Redis server, per exception class')
@exception_counter.increment({ storage: storage_key, exception: ex.class.to_s })
end
2023-05-27 22:25:52 +05:30
def instance_count_cluster_redirection(ex)
# This metric is meant to give a client side view of how often are commands
# redirected to the right node, especially during resharding..
# This metric can be used for Redis alerting and service health monitoring.
@redirection_counter ||= Gitlab::Metrics.counter(:gitlab_redis_client_redirections_total, 'Client side Redis Cluster redirection count, per Redis node, per slot')
@redirection_counter.increment(decompose_redirection_message(ex.message).merge({ storage: storage_key }))
end
2020-07-28 23:09:34 +05:30
def instance_observe_duration(duration)
@request_latency_histogram ||= Gitlab::Metrics.histogram(
:gitlab_redis_client_requests_duration_seconds,
'Client side Redis request latency, per Redis server, excluding blocking commands',
{},
2020-10-24 23:57:45 +05:30
[0.1, 0.5, 0.75, 1]
2020-07-28 23:09:34 +05:30
)
@request_latency_histogram.observe({ storage: storage_key }, duration)
end
2023-05-27 22:25:52 +05:30
def log_exception(ex)
::Gitlab::ErrorTracking.log_exception(ex, storage: storage_key)
end
2020-06-23 00:09:42 +05:30
private
def request_count_key
strong_memoize(:request_count_key) { build_key(:redis_request_count) }
end
def read_bytes_key
strong_memoize(:read_bytes_key) { build_key(:redis_read_bytes) }
end
def write_bytes_key
strong_memoize(:write_bytes_key) { build_key(:redis_write_bytes) }
end
def call_duration_key
strong_memoize(:call_duration_key) { build_key(:redis_call_duration) }
end
def call_details_key
strong_memoize(:call_details_key) { build_key(:redis_call_details) }
end
2023-03-04 22:38:38 +05:30
def cross_slots_key
strong_memoize(:cross_slots_key) { build_key(:redis_cross_slot_request_count) }
end
def allowed_cross_slots_key
strong_memoize(:allowed_cross_slots_key) { build_key(:redis_allowed_cross_slot_request_count) }
end
2020-06-23 00:09:42 +05:30
def build_key(namespace)
"#{storage_key}_#{namespace}"
end
2023-05-27 22:25:52 +05:30
def decompose_redirection_message(err_msg)
redirection_type, _, target_node_key = err_msg.split
{ redirection_type: redirection_type, target_node_key: target_node_key }
end
2020-06-23 00:09:42 +05:30
end
end
end
end