redis 这个 gem 在最新的 4.1 版中开始支持 Redis Cluster。在生产环境需要考虑 Redis 的各个客户端,同时要考虑数据迁移和兼容的问题,升级到 Redis Cluster 要非常谨慎和细心。
我们需要在开发环境搭建一个 Redis Cluster,最方便快捷的方法是使用 docker 和 docker-compose,并且使用配置好的 image。
在 docker-compose.yml 中添加下列代码
version: '3'
services:
redis-cluster:
image: grokzen/redis-cluster
environment:
- IP=0.0.0.0
ports:
- '7000-7007:7000-7007'
使用 docker-compose up -d 启动服务即可。
更新代码
在 Gemfile 中设置 redis gem 的版本为 4.1
gem "redis", "~> 4.1"
在 application.rb 中修改 session_store 和 cache_store
Rails.application.configure do
# Redis Session Store (redis-rails Gem)
config.session_store :redis_store, servers: { cluster: %w[redis://127.0.0.1:7000] }, expires_in: 1.month
# Redis Cache Store (redis-rails Gem)
config.cache_store = :redis_store, { cluster: %w[redis://127.0.0.1:7000] }
# Redis Cache Store (ActiveSupport)
config.cache_store = :redis_cache_store, { cluster: %w[redis://127.0.0.1:7000] }
end
在其他地方使用 Redis Cluster
redis = Redis.new(cluster: %w[redis://127.0.0.1:7000])
分片
从单机变成集群之后,数据分片了,分散到不同机器,但是实际需求要求相关联的 key 分配到相同机器。
因为业务或者性能问题,我们会使用 Redis 的 pipelined、multi 和 Rails.cache.read_multi,这些场景下都需要 key 分配到相同机器。
但是 Redis Cluster 的分片方案是服务端提供分片,规则不是客户端控制的。
针对这些场景 Redis Cluster 提供了 Keys hash tags 的功能,简单来说是:
当一个 key 包含 {} 的时候,就不对整个 key 做 hash,而仅对 {} 包括的字符串做 hash。
redis = Redis.new(cluster: %w[redis://127.0.0.1:7000])
redis.mget('key1', 'key2')
#=> Redis::CommandError (CROSSSLOT Keys in request don't hash to the same slot)
redis.mget('{key}1', '{key}2')
#=> [nil, nil]
总结
本文只是一个简单的例子,不能在生产环境中直接使用。