Redis Cluster架构设计与数据分片原理
Redis Cluster是Redis官方提供的分布式解决方案,通过数据分片实现水平扩展,每个节点负责一部分哈希槽(slot)。数据库运维中,单机Redis在内存容量和吞吐量上存在瓶颈,Redis Cluster通过16384个哈希槽将数据均匀分布到多个节点,同时提供自动故障转移能力。
哈希槽与路由机制
Redis Cluster使用CRC16算法计算key的哈希值,取模16384得到槽位号。每个节点负责一部分槽位。客户端可连接任意节点,如果key不在该节点的槽位范围内,节点返回MOVED重定向响应,客户端缓存路由表后直接连接目标节点。
# 哈希槽计算公式
slot = CRC16(key) mod 16384
# 示例: 3主3从集群的槽位分配
# 节点A: 槽 0-5460 (共5461个)
# 节点B: 槽 5461-10922 (共5462个)
# 节点C: 槽 10923-16383 (共5461个)
# MOVED重定向示例
# 客户端 -> 节点A: SET user:1001 "alice"
# 节点A: CRC16("user:1001") mod 16384 = 12345 -> 属于节点B
# 节点A返回: -MOVED 12345 192.168.1.12:6379
# 客户端缓存路由信息,连接节点B重试
使用hash tag可以强制多个key分配到同一槽位,便于执行多键操作。hash tag的语法是用{}包裹key的一部分,CRC16只计算{}内的内容:
# 不使用hash tag: 三个key可能在不同节点
SET user:1001:profile "alice"
SET user:1001:age "30"
SET user:1001:email "a@test.com"
# 无法执行MGET user:1001:profile user:1001:age user:1001:email (跨节点)
# 使用hash tag: 三个key一定在同一节点
SET {user:1001}:profile "alice"
SET {user:1001}:age "30"
SET {user:1001}:email "a@test.com"
# CRC16("user:1001") mod 16384 = 固定值
# 可以执行 MGET {user:1001}:profile {user:1001}:age {user:1001}:email
集群搭建与环境准备
以6节点集群(3主3从)为例,最小可用配置。每台Redis实例需要独立的配置文件和端口:
# 创建目录结构
mkdir -p /data/redis-cluster/{7000,7001,7002,7003,7004,7005}
# 各节点配置文件 redis.conf
port 7000
bind 0.0.0.0
daemonize yes
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 15000
appendonly yes
appendfilename "appendonly-7000.aof"
dbfilename dump-7000.rdb
dir /data/redis-cluster/7000
logfile /data/redis-cluster/7000/redis.log
# 启动所有节点
for port in 7000 7001 7002 7003 7004 7005; do
redis-server /data/redis-cluster/$port/redis.conf
done
# 检查各节点进程
ps aux | grep redis
# redis-server 0.0.0.0:7000 [cluster]
# redis-server 0.0.0.0:7001 [cluster]
# ...
创建集群与槽位分配
使用redis-cli的–cluster create命令创建集群:
# 创建集群: 3主3从,自动分配槽位和主从关系
redis-cli --cluster create \
192.168.1.10:7000 \
192.168.1.10:7001 \
192.168.1.11:7002 \
192.168.1.11:7003 \
192.168.1.12:7004 \
192.168.1.12:7005 \
--cluster-replicas 1
# 输出:
# >>> Performing hash slots allocation on 6 nodes...
# Master[0] -> Slots 0-5460 -> 192.168.1.10:7000
# Master[1] -> Slots 5461-10922 -> 192.168.1.11:7002
# Master[2] -> Slots 10923-16383 -> 192.168.1.12:7004
# Adding replica 192.168.1.10:7001 to 192.168.1.10:7000
# Adding replica 192.168.1.11:7003 to 192.168.1.11:7002
# Adding replica 192.168.1.12:7005 to 192.168.1.12:7004
# 查看集群状态
redis-cli -c -p 7000 cluster info
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# 查看节点信息
redis-cli -c -p 7000 cluster nodes
# id... 192.168.1.10:7000@17000 myself,master - 0 0 0 connected 0-5460
# id... 192.168.1.11:7002@17002 master - 0 0 0 connected 5461-10922
# id... 192.168.1.12:7004@17004 master - 0 0 0 connected 10923-16383
# id... 192.168.1.10:7001@17001 slave ... 192.168.1.10:7000
# ...
-c参数启用集群模式,客户端自动处理MOVED重定向。建议使用支持集群协议的客户端库(如Jedis/Lettuce的cluster模式),客户端会缓存槽位路由表,避免每次请求都触发重定向。
故障转移与脑裂防护
当主节点宕机时,其从节点自动升级为新主节点。故障检测通过Gossip协议实现,节点间定时交换心跳信息:
# 故障转移流程:
# 1. 节点B检测到主节点A超时(cluster-node-timeout)
# 2. 节点B标记A为PFAIL (主观下线)
# 3. B向其他节点广播PFAIL消息
# 4. 超过半数主节点确认A不可达 -> 标记FAIL (客观下线)
# 5. A的从节点发起选举,获得多数主节点投票后升级为master
# 6. 新主节点接管A的所有槽位
# 手动故障转移
redis-cli -p 7003 cluster failover
# 从节点7003发起故障转移,升级为主节点
# 手动指定新主节点
redis-cli -p 7003 cluster failover TAKEOVER # 强制接管不检查
# 查看集群健康
redis-cli -p 7000 cluster info | grep -E "state|slot"
# cluster_state:ok
# cluster_slots_ok:16384
cluster-node-timeout是影响故障转移速度的关键参数。默认15000ms(15秒),生产环境建议设置为5000-10000ms以加快故障感知。但过短的阈值可能在网络抖动时触发误判。
集群扩容与缩容操作
# 扩容: 添加新主节点7006和新从节点7007
# 1. 启动新节点
redis-server /data/redis-cluster/7006/redis.conf
redis-server /data/redis-cluster/7007/redis.conf
# 2. 将新节点加入集群
redis-cli --cluster add-node 192.168.1.13:7006 192.168.1.10:7000
redis-cli --cluster add-node 192.168.1.13:7007 192.168.1.10:7000 --cluster-slave --cluster-master-id <7006的node-id>
# 3. 迁移槽位到新节点
redis-cli --cluster reshard 192.168.1.10:7000 \
--cluster-from <源节点ID1>,<源节点ID2> \
--cluster-to <7006的node-id> \
--cluster-slots 4096 \
--cluster-yes
# 缩容: 移除节点
# 1. 将待移除节点的槽位迁移到其他节点
redis-cli --cluster reshard 192.168.1.10:7000 \
--cluster-from <7006的node-id> \
--cluster-to <目标节点ID> \
--cluster-slots 4096 \
--cluster-yes
# 2. 移除节点
redis-cli --cluster del-node 192.168.1.10:7000 <7007的node-id>
redis-cli --cluster del-node 192.168.1.10:7000 <7006的node-id>
槽位迁移过程中集群仍可正常服务,迁移中的槽位被标记为MIGRATING状态,写入请求会重定向到目标节点。Redis Cluster在单节点故障时通过从节点自动接管保障可用性,多节点同时故障时影响对应槽位的数据。Redis缓存策略的制定需要根据数据热度和一致性要求选择合适的集群规模和副本数量。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rediscluster-ji-qun-da-jian-yu-shu-ju-fen-pian-lu-you-ji/