哈希槽(hash slot)是Redis Cluster进行数据分片的基础单位。整个集群共有16384个槽位,编号从0到16383,每个主节点负责其中一部分槽位。当客户端写入或读取一个键时,集群先对键名做CRC16运算并对16384取模,得到槽位号,再根据槽位与节点的映射关系定位到具体节点。理解哈希槽的原理,是掌握Redis集群架构和日常运维的必修课。

哈希槽的基本原理与计算方式
Redis Cluster并没有采用传统的一致性哈希环,而是引入了固定数量的哈希槽作为键与节点之间的中间层。这种间接层带来的最大好处是:节点增减时,只需要调整槽位与节点的归属关系,而不需要改变键到槽位的映射规则。键属于哪个槽是永远不变的,变的只是这个槽归哪个节点管理。
槽位的计算公式非常简单:slot = CRC16(key) mod 16384。CRC16是一种标准的循环冗余校验算法,能产生16位的哈希值,取值范围是0到65535,对16384取模后恰好落在0到16383之间。可以在任意一台Redis节点上验证这个计算结果:
redis-cli -c -h 192.168.0.1 -p 6379
> cluster keyslot user:1001
(integer) 7638
> cluster keyslot {user}:1001
(integer) 9990
上面第二个命令展示了哈希标签(hash tag)的用法。当键名中包含花括号时,Redis只会对花括号内的内容做CRC16计算。这样一来,{user}:1001和{user}:1002会被分配到同一个槽位,从而支持多键操作。但要注意,过度使用哈希标签会导致数据倾斜,让某个节点承担过大的压力,使用前应评估业务的数据分布情况。
MOVED与ASK重定向:客户端如何找到正确的节点
集群模式下,客户端可以向任意节点发送命令。如果键所在的槽位恰好由该节点负责,命令直接执行;否则节点会返回一个重定向响应。重定向分为两种情况,理解它们的区别对排查线上问题非常重要。
第一种是MOVED重定向,表示槽位已经稳定地归属于另一个节点,客户端应当更新本地的槽位映射表,后续请求直接发往新节点。第二种是ASK重定向,出现在槽位正在迁移的中间状态:源节点仍持有部分键,目的节点已接收另一部分键。ASK告诉客户端这次请求临时去问目的节点,但不要更新本地映射,因为迁移完成后映射还会变。两者的对比可以用表格梳理:
| 对比项 | MOVED | ASK |
|---|---|---|
| 含义 | 槽位已永久归属其他节点 | 槽位正在迁移,临时重定向 |
| 客户端行为 | 更新本地槽位表并重发命令 | 仅本次携带ASKING重发,不更新映射 |
| 出现时机 | 槽位分配完成后的正常状态 | cluster迁移过程中的瞬时状态 |
智能客户端如Jedis、Lettuce、redis-py-cluster都会在启动时通过cluster slots命令拉取完整的槽位分布并缓存在本地,正常情况下几乎不会触发重定向。如果监控中发现大量MOVED重定向,通常说明客户端缓存过期或集群刚做过扩容,可以考虑升级客户端版本或重启应用刷新映射。
槽位迁移实操与扩缩容流程
当需要给集群新增节点时,并不是简单把节点加入集群就完事,还必须把一部分槽位从现有节点迁移到新节点。可以使用redis-cli --cluster reshard交互式完成,也可以手动执行底层命令来精细控制。手动迁移的核心命令如下:
# 1. 在目标节点上声明接管槽位(多个源节点则多次执行) redis-cli cluster setslot 8191 importing 6192a7... # 2. 在源节点上声明迁出槽位 redis-cli cluster setslot 8191 migrating 8e3f5a... # 3. 批量迁移键 redis-cli cluster getkeysinslot 8191 100 redis-cli -c migrate 192.168.0.2 6380 "" 0 5000 KEYS key1 key2 # 4. 迁移完成后,通知所有节点槽位归属 redis-cli cluster setslot 8191 node 8e3f5a...
迁移过程中有一个容易踩坑的地方:步骤4必须对集群中的每一个节点都执行一遍,因为槽位归属信息是每个节点独立维护的。如果漏掉某个节点,就会出现部分节点认为槽位属于A、另一部分认为属于B的脑裂状态,客户端会收到反复重定向甚至报错。生产环境建议优先使用redis-cli --cluster系列封装命令,它会自动处理这些细节。
缩容则相反:先把要下线节点上的所有槽位迁移到其他节点,确认槽数为零后再执行cluster forget移除节点。可以通过cluster nodes命令查看每个节点负责的槽位区间,迁移过程中务必关注源节点的内存和复制积压缓冲区,避免大批量MIGRATE造成主从复制延迟。
为什么是16384个槽而不是65536个
这是Redis作者antirez亲自回答过的经典问题。CRC16本身能产生65536个值,为什么只取一半作为槽数?核心原因在于心跳包的大小。集群节点之间通过PING和PONG消息交换槽位信息,如果把槽位图完整传输,用bitmap表示时16384个槽只需要2KB,而65536个槽需要8KB。心跳是高频消息,槽位图过大会显著增加网络带宽消耗。
第二个原因是集群规模的上限设计。Redis Cluster官方建议最多1000个主节点,16384个槽在千级节点规模下分配粒度已经足够精细,平均每个节点也能分到16个以上的槽位,再多的槽数并无实际收益。第三个原因则是槽位图压缩效率:节点数较少时,槽位分布相对集中,bitmap可以用压缩编码传输,槽数越少压缩效果越明显。
从工程角度看,这个设计体现了够用就好的取舍思维。哈希槽方案相比一致性哈希环还有一个显著优势:迁移时可以精确到单个槽位,数据移动的最小单位明确,便于评估迁移量;而一致性哈希在节点变动时影响的是哈希环上的一段区间,边界难以精确控制。这也是Redis选择固定槽数的深层次原因。掌握哈希槽机制后,无论是排查集群故障还是做容量规划,都会更加得心应手。
Redis哈希槽Redis Cluster一致性哈希修改时间:2026-09-02 21:45:11