跳至内容 跳至搜索

Redis 缓存存储

部署注意事项:请注意使用**专用 Redis 缓存**,而不是指向持久化的 Redis 服务器(例如,用作 Active Job 队列的服务器)。Redis 无法很好地处理混合使用模式,并且默认情况下不会过期缓存项。

Redis 缓存服务器设置指南: redis.io/topics/lru-cache

  • 支持原生 Redis、hiredis 和 Redis::Distributed

  • 支持使用 Redis::Distributed 在 Redis 之间进行类似 Memcached 的分片。

  • 容错。如果 Redis 服务器不可用,则不会引发异常。Cache 的读取操作都将视为未命中,写入操作将被丢弃。

  • 本地缓存。块/中间件作用域内的热门内存主缓存。

  • 支持 read_multiwrite_multi 以用于 Redis 的 mget/mset。使用 Redis::Distributed 4.0.1+ 以支持分布式 mget。

  • 支持 delete_matched 以用于 Redis KEYS glob 模式。

方法
C
D
I
N
R
S

常量

DEFAULT_ERROR_HANDLER = -> (method:, returning:, exception:) do if logger logger.error { "RedisCacheStore: #{method} 失败,返回 #{returning.inspect}:#{exception.class}:#{exception.message}" } end ActiveSupport.error_reporter&.report( exception, severity: :warning, source: "redis_cache_store.active_support", ) end
 
DEFAULT_REDIS_OPTIONS = { connect_timeout: 1, read_timeout: 1, write_timeout: 1, }
 

Attributes

[R] redis

类公共方法

new(error_handler: DEFAULT_ERROR_HANDLER, **redis_options)

创建一个新的 Redis 缓存存储。

有几种方法可以提供缓存使用的 Redis 客户端

  1. :redis 参数可以是

    • Redis 实例。

    • 包装 Redis 实例的 ConnectionPool 实例。

    • 返回 Redis 实例的代码块。

  2. :url 参数可以是

    • 用于创建 Redis 实例的字符串。

    • 用于创建 Redis::Distributed 实例的字符串数组。

如果最终的 Redis 实例不是 ConnectionPool,它将被包装在一个中使用 ActiveSupport::Cache::Store::DEFAULT_POOL_OPTIONS。这些选项可以通过 :pool 参数覆盖,也可以通过 +:pool: false+ 禁用池。

Option  Class       Result
:redis  Object  ->  options[:redis]
:redis  Proc    ->  options[:redis].call
:url    String  ->  Redis.new(url: …)
:url    Array   ->  Redis::Distributed.new([{ url: … }, { url: … }, …])

默认情况下不设置命名空间。如果 Redis 缓存服务器与其他应用程序共享,请提供一个:namespace: 'myapp-cache'

默认启用压缩,阈值为 1kB,因此大于 1kB 的缓存值将被自动压缩。通过传递 compress: false 禁用,或通过传递 compress_threshold: 4.kilobytes 更改阈值。

默认情况下,缓存项不设置过期时间。Redis 应配置为具有驱逐策略,以便在达到最大内存时自动删除最近最少使用或最不常使用的键。有关缓存服务器设置,请参阅 redis.io/topics/lru-cache

默认不设置“惊群效应” TTL。这可用于避免在热门缓存项过期时发生“惊群效应”缓存写入。有关更多信息,请参阅 ActiveSupport::Cache::Store#fetch

设置 skip_nil: true 将不会缓存 nil 结果

cache.fetch('foo') { nil }
cache.fetch('bar', skip_nil: true) { nil }
cache.exist?('foo') # => true
cache.exist?('bar') # => false
# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 155
def initialize(error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
  universal_options = redis_options.extract!(*UNIVERSAL_OPTIONS)
  redis = redis_options[:redis]

  already_pool = redis.instance_of?(::ConnectionPool) ||
                 (redis.respond_to?(:wrapped_pool) && redis.wrapped_pool.instance_of?(::ConnectionPool))

  if !already_pool && pool_options = self.class.send(:retrieve_pool_options, redis_options)
    @redis = ::ConnectionPool.new(pool_options) { self.class.build_redis(**redis_options) }
  else
    @redis = self.class.build_redis(**redis_options)
  end

  @error_handler = error_handler

  super(universal_options)
end

supports_cache_versioning?()

声明缓存版本支持。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 60
def self.supports_cache_versioning?
  true
end

实例公共方法

cleanup(options = nil)

Cache Store API 实现。

删除过期的条目。由 Redis 的最近最少使用/最不常使用过期策略原生处理,因此不支持手动清理。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 301
def cleanup(options = nil)
  super
end

clear(options = nil)

清除所有 Redis 服务器上的整个缓存。如果缓存已进行命名空间隔离,则在共享服务器上使用是安全的。

容错:引发错误。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 309
def clear(options = nil)
  failsafe :clear do
    if namespace = merged_options(options)[:namespace]
      delete_matched "*", namespace: namespace
    else
      redis.then { |c| c.flushdb }
    end
  end
end

decrement(name, amount = 1, options = nil)

使用 Redis decrby 原子操作符递减缓存的整数值。返回更新后的值。

如果键未设置或已过期,则会设置为 -amount

cache.decrement("foo") # => -1

要设置特定值,请调用 write 并传递 raw: true

cache.write("baz", 5, raw: true)
cache.decrement("baz") # => 4

递减非数字值或未用 raw: true 写入的值将失败并返回 nil

要稍后读取该值,请调用 read_counter

cache.decrement("baz") # => 3
cache.read_counter("baz") # 3

容错:引发错误。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 286
def decrement(name, amount = 1, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument :decrement, key, amount: amount do
    failsafe :decrement do
      change_counter(key, -amount, options)
    end
  end
end

delete_matched(matcher, options = nil)

Cache Store API 实现。

支持 Redis KEYS glob 模式

h?llo matches hello, hallo and hxllo
h*llo matches hllo and heeeello
h[ae]llo matches hello and hallo, but not hillo
h[^e]llo matches hallo, hbllo, ... but not hello
h[a-b]llo matches hallo and hbllo

如果您想按原样匹配特殊字符,请使用 \ 进行转义。

更多信息请参阅 redis.io/commands/KEYS

容错:引发错误。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 210
def delete_matched(matcher, options = nil)
  unless String === matcher
    raise ArgumentError, "Only Redis glob strings are supported: #{matcher.inspect}"
  end
  pattern = namespace_key(matcher, options)

  instrument :delete_matched, pattern do
    redis.then do |c|
      cursor = "0"
      # Fetch keys in batches using SCAN to avoid blocking the Redis server.
      nodes = c.respond_to?(:nodes) ? c.nodes : [c]

      nodes.each do |node|
        begin
          cursor, keys = node.scan(cursor, match: pattern, count: SCAN_BATCH_SIZE)
          node.unlink(*keys) unless keys.empty?
        end until cursor == "0"
      end
    end
  end
end

increment(name, amount = 1, options = nil)

使用 Redis incrby 原子操作符递增缓存的整数值。返回更新后的值。

如果键未设置或已过期,则会设置为 amount

cache.increment("foo") # => 1
cache.increment("bar", 100) # => 100

要设置特定值,请调用 write 并传递 raw: true

cache.write("baz", 5, raw: true)
cache.increment("baz") # => 6

递增非数字值或未用 raw: true 写入的值将失败并返回 nil

要稍后读取该值,请调用 read_counter

cache.increment("baz") # => 7
cache.read_counter("baz") # 7

容错:引发错误。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 254
def increment(name, amount = 1, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument :increment, key, amount: amount do
    failsafe :increment do
      change_counter(key, amount, options)
    end
  end
end

inspect()

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 173
def inspect
  "#<#{self.class} options=#{options.inspect} redis=#{redis.inspect}>"
end

read_multi(*names)

Cache Store API 实现。

一次读取多个值。返回一个包含请求键 -> 获取值的哈希。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 181
def read_multi(*names)
  return {} if names.empty?

  options = names.extract_options!
  options = merged_options(options)
  keys    = names.map { |name| normalize_key(name, options) }

  instrument_multi(:read_multi, keys, options) do |payload|
    read_multi_entries(names, **options).tap do |results|
      payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
    end
  end
end

stats()

从 Redis 服务器获取信息。

# File activesupport/lib/active_support/cache/redis_cache_store.rb, line 320
def stats
  redis.then { |c| c.info }
end