1. Redis Cluster分片核心机制
Redis Cluster 是 Redis 官方提供的分布式分片方案,它把整个键空间划分为 16384 个哈希槽(hash slot),每个主节点负责其中一部分槽位。客户端写入一个键时,先对键名做 CRC16 计算,再对 16384 取模,得到该键所属的槽号,然后由持有该槽的节点处理。理解这套机制,是后续做扩缩容、槽迁移和故障转移的前提。
一、哈希槽:分片的最小单位
槽号的计算公式为:
slot = CRC16(key) mod 16384
这里有一个关键细节:如果键名中包含 {...},则只对花括号内的内容做哈希,这称为 hash tag。例如 user:{1001}:name 和 user:{1001}:age 的哈希对象都是 1001,因此落在同一个槽、同一个节点上。这让需要原子性多键操作(如 MGET、事务、Lua 脚本)的键可以强制共槽。
16384 这个数字不是随意的。集群节点之间通过心跳包交换槽位信息,每个节点用一张 16384 位的位图(bitmap)表示自己负责的槽,即 2KB。如果槽数取 65536,位图就是 8KB,心跳包会明显变大。在集群规模通常不超过 1000 个节点的前提下,16384 已经足够均匀,同时把通信开销压到较低水平。
槽的分配结果由集群元数据维护。每个节点都保存一份完整的槽位映射表,记录“哪个槽属于哪个节点”。客户端访问任意节点,如果该节点不持有目标槽,会返回 MOVED 重定向;如果槽正在迁移,则可能返回 ASK 重定向。两者的区别在于:MOVED 表示槽的归属已经永久改变,客户端应更新本地槽映射缓存;ASK 表示只是临时到目标节点取一次数据,不更新缓存。
二、节点通信协议与集群总线
集群中的每个节点都开放两个端口:
- 客户端端口:默认 6379,用于处理普通命令,如
GET、SET。 - 集群总线端口:默认是客户端端口 + 10000,即 16379,用于节点之间的二进制协议通信。
集群总线使用一套独立的二进制协议,而不是 RESP 文本协议。节点通过它交换以下几类消息:
- MEET:邀请一个新节点加入集群。
- PING / PONG:心跳探测,携带自身状态、负责的槽位、配置纪元(config epoch)等信息。
- FAIL:广播某个节点已客观下线(fail)。
- PUBLISH:在集群范围内传播 Pub/Sub 消息。
- UPDATE:通知槽位归属变更。
每个节点每秒会向随机挑选的几个节点发送 PING,同时也会向最久未通信的节点发送 PING。收到 PONG 后,双方刷新对彼此的“最后通信时间”。如果某个节点在 cluster-node-timeout(默认 15000 毫秒)内一直没有响应,就会被标记为疑似下线(PFAIL);当超过半数主节点都报告该节点 PFAIL 时,它被判定为客观下线(FAIL),随后触发故障转移。
节点之间还通过 Gossip 协议 传播信息。每个 PING/PONG 包会附带随机几个其他节点的状态,这样集群状态能在有限跳数内扩散到全网,而不需要中心节点。这也是 Redis Cluster 去中心化设计的核心。
三、拓扑结构与槽分配示例
一个典型的三主三从集群如下:节点 A、B、C 为主节点,A1、B1、C1 分别为它们的从节点。槽的分配可以是:
| 主节点 | 负责槽范围 | 从节点 |
|---|---|---|
| A | 0 – 5460 | A1 |
| B | 5461 – 10922 | B1 |
| C | 10923 – 16383 | C1 |
从节点默认只复制主节点数据,不处理写请求。当主节点被判定 FAIL 后,其从节点会发起选举,获得多数主节点投票后晋升为新主节点,接管原主节点的槽位,并广播 UPDATE 消息。整个过程由集群总线完成,客户端只需根据 MOVED 重定向更新路由。
下面这张图展示了三主三从集群中,客户端请求如何经过槽计算、节点路由,以及节点之间通过集群总线交换心跳与槽位信息的关系。
四、槽迁移与重定向的配合
扩容时,需要把部分槽从旧节点迁移到新节点。迁移以槽为单位,使用 CLUSTER SETSLOT、CLUSTER GETKEYSINSLOT、MIGRATE 等命令完成。迁移过程中,源节点对已迁移的键返回 ASK 重定向,对尚未迁移的键正常处理;目标节点则临时接受 ASKING 请求。迁移完成后,通过 CLUSTER SETSLOT ... NODE ... 把槽的归属正式交给新节点,此后客户端收到 MOVED 并更新路由表。
五、集群总线与故障判定
集群总线不仅传递心跳,还承担故障判定和配置传播。每个节点维护一个“最后通信时间”表,超过 cluster-node-timeout 未收到 PONG 就标记 PFAIL。PFAIL 只是本地判断,需要通过 Gossip 扩散,当多数主节点都认为某节点 PFAIL 时,才升级为 FAIL。FAIL 消息一旦广播,该节点的从节点就会发起选举,获得多数主节点投票后晋升,接管槽位并广播 UPDATE。
这套机制的关键参数是 cluster-node-timeout。设置过小,网络抖动容易误判下线,引发不必要的故障转移;设置过大,真实故障时切换变慢,影响可用性。一般建议根据实际网络 RTT 和业务容忍度在 5000~30000 毫秒之间调整,并配合 cluster-replica-validity-factor 控制从节点参与选举的资格。
总结来看,Redis Cluster 的分片核心可以归纳为三点:槽是分片的最小单位,16384 个槽通过 CRC16 映射键;节点通过集群总线交换状态,用 Gossip 扩散槽位和故障信息;客户端通过 MOVED/ASK 重定向找到正确节点。理解这三者的配合,才能在扩缩容、迁移和故障转移时做出正确判断。