1. 引言
很多刚接触 Redis Cluster 的同学都会有一个疑问:为什么集群要设计成 16384 个槽(slot),而不是 1000 个、10000 个或者更多?这篇文章就来彻底讲清楚 16384 个槽到底是什么、怎么用,以及为什么偏偏是这个数字。
2. 槽(Slot)是什么
Redis Cluster 并没有使用一致性哈希,而是采用了一种叫做「哈希槽」(hash slot)的机制。
简单来说,整个集群被逻辑上划分为16384 个槽,编号从0到16383。每个键(key)都会通过下面的公式被映射到其中一个槽上:
HASH_SLOT = CRC16(key) % 16384也就是说,先对 key 做 CRC16 校验,得到一个 16 位的整数,再对 16384 取模,最终得到该 key 所属的槽编号。
3. 槽与节点的关系
槽是数据分布的最小逻辑单元,而节点(master)是真正存储数据的物理单元。
- 每个 master 节点负责一部分槽;
- 一个槽只能属于一个 master;
- 所有槽都被分配完毕后,集群才处于正常状态(
cluster_state:ok)。
例如一个 3 主节点的集群,可以这样分配:
| 节点 | 负责的槽范围 |
|---|---|
| Master A | 0 – 5460 |
| Master B | 5461 – 10922 |
| Master C | 10923 – 16383 |
当客户端要读写某个 key 时,先算出它的槽编号,再通过集群的「槽 → 节点」映射表,直接定位到对应的 master 节点,从而完成请求。
4. 为什么是 16384
16384 这个数字并不是随便定的,它背后有性能和内存两方面的考量。
4.1 心跳包要尽量小
集群中的每个节点都会通过 Gossip 协议定期广播自己的状态。心跳包中需要携带「本节点负责哪些槽」的位图信息。
如果用 16384 个槽,每个槽只占 1 个 bit,那么完整的槽位图大小就是:
16384 / 8 = 2048 字节 = 2 KB这个体积非常小,可以轻松放进心跳包里,网络开销很低。
4.2 槽数量不能太少
如果槽数量太少,比如只有 100 个,那么当集群扩容、缩容或做数据迁移时,每个槽里包含的 key 会非常多,导致迁移粒度太粗、数据倾斜明显,很难做到均衡。
4.3 槽数量不能太多
如果槽数量太多,比如 65536 个,虽然迁移粒度更细,但会带来两个问题:
- 槽位图会变成
65536 / 8 = 8 KB,心跳包明显变大,网络开销增加; - 节点间同步槽信息、维护映射表的成本也会上升。
所以 16384 是一个在「迁移粒度」和「通信开销」之间取得平衡的经验值。
5. 槽的迁移
当集群需要扩容、缩水或重新平衡时,实际上做的事情就是「槽迁移」。
迁移过程是增量的:把某个槽从源节点迁移到目标节点时,槽内的 key 会一批一批地搬过去,期间集群仍然可以对外提供服务。
CLUSTER SETSLOT <slot> MIGRATING <target_node_id> CLUSTER SETSLOT <slot> IMPORTING <source_node_id>迁移完成后,槽的归属关系更新,客户端也会通过MOVED或ASK重定向拿到最新的槽映射。
6. 总结
Redis Cluster 的 16384 个槽,本质上是一张把「键空间」均匀切分出来的逻辑地图:
- 每个 key 通过
CRC16(key) % 16384定位到唯一槽; - 每个 master 负责一部分槽;
- 槽的迁移就是集群扩容、缩容和再平衡的核心手段;
- 16384 这个数字,是官方在迁移粒度、心跳包大小和内存开销之间权衡后的最佳选择。
理解了槽,你就理解了 Redis Cluster 的数据分布与扩缩容原理。