1 说法一因为CRC16会输出16bit的结果可以看作是一个分布在 0~2^16-1 之间的数redis的作者测试发现这个数对 2^14 求模的会将key在 0-2^14-1 之间分布得很均匀 2^14 即163842 说法二为了节省存储空间每个节点用一个Bitmap记录节点对应的槽2k 210248 16384也就是说每个节点用2k的内存空间总共16384个比特位就可以存储该结点对应了哪些槽。Bitmap记录节点对应的槽有两个作用判断key是不是归于当前节点当一个客户端发送来一个key时通过CRC(16) / 16384 计算出该key归属的槽solt然后计算检查 (myslots[slot3] (slot7)) 1一条位运算指令判断key是不是归于当前节点。[只需要了解即可不用追究位运算细节]redis Cluster 节点之间通过 Gossip 消息同步集群状态。每个节点需要定期广播 自己负责的槽位集合以便其他节点更新全局槽映射表。如果直接发送槽号列表如 [0,1,2,…5000]需要成千上万个整数几 KB 到几十 KB而发送一个 2KB 的位图 就能完整表示所有槽的归属网络开销小且固定。补充全局槽映射表它是一个长度为16384的数组数组的下标是槽号0~16383对应的值是该槽归属的主节点信息通常是指向节点结构体的指针或者节点ID。用途客户端请求到达任意节点时节点查这个表知道该把请求转发给谁或返回 MOVED。问已经有全局槽映射表为什么还需要bitmap表示节点自身有哪些槽位?很好的问题表面上看确实有冗余但两者服务不同的场景和需求同时存在是为了性能、消息传输和代码逻辑的清晰。1. 本质上的信息重叠与用途分离全局槽映射表slots[16384]记录每个槽由哪个节点负责。用途客户端请求到达任意节点时节点查这个表知道该把请求转发给谁或返回 MOVED。每个节点的位图myslots2KB记录当前节点负责哪些槽。用途快速判断“这个槽是不是我管的”以及集群内部通信时高效地告诉别人我管哪些槽。虽然slots[slot] myself也能判断是否自己负责但位图有独特优势。2. 性能位操作比指针比较更轻量判断一个槽是否属于当前节点用位图检查(myslots[slot3] (slot7)) 1一条位运算指令。用全局表读取slots[slot]一个指针然后与myself指针比较需要两次内存访问和一次比较。在极高并发如每秒几十万请求下位图的微秒级优势会被放大。更重要的是Redis 常需要批量判断如计算自己负责的槽总数、遍历所有属于自己的槽进行迁移用位图可以用memcpy、位计数popcount等高效操作比循环检查 16384 个数组元素快得多。3. 消息传输位图是 Gossip 协议的压缩载体Redis Cluster 节点之间通过 Gossip 消息同步集群状态。每个节点需要定期广播自己负责的槽位集合以便其他节点更新全局表。如果直接发送槽号列表如[0,1,2,...5000]需要成千上万个整数几 KB 到几十 KB而发送一个2KB 的位图就能完整表示所有槽的归属网络开销小且固定。其他节点收到位图后只需按位解析就能重构该节点的槽信息并更新自己的全局映射表。4. 容错和独立性全局映射表是一个逻辑汇总视图可能因为消息延迟或丢包暂时不一致。而每个节点自身维护的位图是权威数据节点自己知道确切负责哪些槽。当节点发现全局表中的某些槽与自己位图不一致时会触发修复如通过CLUSTER BUMPEPOCH或配置更新。5. 历史与代码组织Redis 最早实现集群时就设计了clusterNode-slots位图每个节点负责的槽后来为了方便全局路由才增加了server.cluster-slots数组。两个结构并存各有调用场景需要“给定槽 → 节点”时用全局数组。需要“给定节点 → 它负责的槽集合”时用该节点的位图。总结不是“有了全局表就不需要位图”而是两者从不同维度建模数据全局表是槽为中心槽 → 节点加速路由。位图是节点为中心节点 → 槽集合加速节点自身的判断、迁移和 Gossip 广播。内存占用上每个节点多 2KB 完全可接受带来的性能、网络和代码清晰度收益却很大。如果去掉位图许多操作会变得笨拙且低效。