在 Redis Cluster 中,一个
SET user:1001:name Alice命令,是如何被准确路由到正确的节点的? 如果发错了节点,又是谁在背后默默“指路”? 本文带你深入 Redis Cluster 的核心机制:Key → Slot → Node 的完整寻址链路。
如果你用过 Redis Cluster,一定听说过 “16384 个槽”、“CRC16 哈希”、“MOVED 重定向”这些概念。但你是否真正理解:
- 为什么 key 能稳定映射到同一个 slot?
- 客户端怎么知道该连哪个节点?
- 当 key 不在当前节点时,是服务器转发,还是客户端重试?
今天,我们就从 底层原理 出发,彻底讲清楚 Redis Cluster 的数据分布与路由机制。
一、Key → Slot:确定性哈希,全局一致
Redis Cluster 将整个 key 空间划分为 16384 个 slots(槽),编号 0 ~ 16383。
每个 key 通过以下公式确定其所属 slot:
slot = CRC16(key) % 16384
CRC16是一种快速、低冲突的哈希算法;% 16384确保结果落在有效槽范围内;- 最关键的是:这个计算是确定性的 —— 无论在哪台机器、哪个客户端,同一个 key 永远得到相同的 slot。
📌 示例:
key = "order:20240501"
→ CRC16("order:20240501") = 20000
→ slot = 20000 % 16384 = 3616
✅ 所有节点和客户端对 “key 属于哪个 slot” 达成共识,这是分布式一致性的基石。
二、Slot → Node:集群元数据,每个节点都“心中有图”
光知道 slot 还不够,还得知道 哪个节点负责这个 slot。
Redis Cluster 采用 去中心化架构,没有中心协调服务(如 ZooKeeper)。那它是如何让每个节点都知道全局拓扑的?
答案是:Gossip 协议。
每个节点都维护一份完整的集群视图
执行 CLUSTER NODES,你会看到类似输出:
a1b2c3... 192.168.1.10:7001 master - connected 0-5460
d4e5f6... 192.168.1.11:7002 master - connected 5461-10922
g7h8i9... 192.168.1.12:7003 master - connected 10923-16383
即使你在 192.168.1.10 上执行,也能看到其他节点的 slot 范围!
Gossip 如何同步?
- 节点之间定期交换 PING/PONG 消息;
- 消息中携带部分集群元数据(包括 slot 分配);
- 信息像“流言”一样扩散,最终所有节点达成一致。
💡 这种设计避免了单点故障,也无需外部依赖。
三、客户端路由:智能缓存 + 本地计算
Redis Cluster 不要求客户端连接所有节点,而是依赖 智能客户端(如 Lettuce、JedisCluster、Redisson)。
客户端工作流程:
-
启动时:连接任意一个集群节点;
-
获取拓扑:发送
CLUSTER SLOTS,拉取完整的 slot → node 映射; -
本地缓存:将映射表存入内存(如
Map<Integer, HostAndPort>); -
执行命令时
:
- 计算
slot = CRC16(key) % 16384; - 查缓存,找到目标节点;
- 直接向该节点发送命令。
- 计算
✅ 正常情况下,一次网络请求直达目标,无跳转、无延迟。
四、MOVED 重定向:客户端自我纠正,非服务端转发!
但缓存可能过期(如集群扩容、故障转移),客户端可能发错节点。
场景:
-
客户端把
key="user:1001"(slot=12345)发给了 Node A; -
Node A 负责 slots
0-5460,发现 slot 12345 不归自己管; -
于是返回:
(error) MOVED 12345 192.168.1.11:7002
关键点来了:
❌ Node A 不会把请求转发给 Node B! ✅ 它只是告诉客户端:“去 192.168.1.11:7002 找”。
客户端收到 MOVED 后:
- 解析出新地址;
- 更新本地缓存(slot 12345 → Node B);
- 自动重试命令,这次直连正确节点。
流程图:
客户端 → Node A(错误) → 返回 MOVED
客户端 → 更新缓存 → 重试 → Node B(正确) → 成功
🔥 Redis Cluster 故意不做服务端转发,原因有三:
- 避免级联延迟;
- 防止热点节点成为代理瓶颈;
- 保持节点职责单一(只处理自己负责的数据)。
五、特殊场景:ASK 重定向(迁移中)
当 slot 正在迁移(reshard)时,可能出现 ASK 错误:
(error) ASK 12345 192.168.1.11:7002
客户端处理方式:
- 先向目标节点发送
ASKING命令(临时标记); - 再发送原命令;
- 不更新本地缓存(因为迁移未完成,归属未定)。
⚠️
ASK是临时状态,MOVED才是永久变更。
六、Bonus:Hash Tag —— 强制多 key 落在同一 slot
Redis Cluster 默认不支持跨 slot 的多 key 操作。但你可以用 {} 包裹共同标识:
user:{1001}:name
user:{1001}:balance
order:{1001}:list
→ 只对 {1001} 做 CRC16 → 所有 key 落在同一 slot → 可安全用于 Lua 或事务。
💡 这是实现“聚合根”原子操作的唯一方式。
结语
Redis Cluster 的精妙之处在于:
- 用确定性哈希保证数据分布可预测;
- 用 Gossip 协议实现去中心化一致性;
- 用客户端智能路由减少跳转开销;
- 用 MOVED/ASK 实现弹性容错。