Redis Cluster 的哈希槽如何分配?扩容迁移有什么影响?
结论先行:Cluster 把键空间固定划分为 16384 个哈希槽,每个 key 通过 CRC16(key) % 16384 归属某个槽,槽再分配给不同主节点(每个主节点可带从节点做高可用)。扩缩容的本质是迁移槽:把部分槽及其中的 key 从源节点搬到目标节点,期间会有短暂的访问重定向与性能抖动。
一、哈希槽机制
- 槽的划分:16384 个槽由集群各主节点分片持有,节点增减只影响槽的归属,key 与节点的映射关系通过槽间接完成;
- key 定位:CRC16(key) % 16384 得到槽号,再查槽与节点的映射;使用哈希标签可以让指定 key 落在同一槽,例如 user:{1001}:cart 中的 {1001} 参与哈希计算,保证多 key 操作在同一节点执行;
- 客户端路由:智能客户端缓存 slot 与节点的映射表,收到 MOVED 重定向时更新缓存重新请求;
- 从节点角色:从节点不直接持有槽,只做副本备份,主节点故障时由对应从节点提升接管其槽位。
二、MOVED 与 ASK 的区别
| 重定向 | 触发时机 | 客户端处理 |
|---|---|---|
| MOVED | 槽已彻底迁移到目标节点 | 更新本地槽映射,下次直接访问新节点 |
| ASK | 槽迁移过程中,key 正在搬移 | 只对本次请求跟随到目标节点,不更新映射 |
三、扩容与迁移影响
- 扩容流程:新节点加入集群(CLUSTER MEET)→ 执行 reshard 把源节点部分槽迁给新节点;
- 迁移过程:源节点把槽置为 migrating、目标节点置为 importing,key 按批迁移;迁移期间命中的 key 若已搬走,源节点返回 ASK 让客户端去目标节点找;
- 主要影响:客户端槽映射刷新产生零星重试;超大 key 迁移耗时且占带宽;迁移期间相关 key 的访问延迟上升,建议低峰执行并控制迁移并发;
- 限制:多 key 命令、事务、Lua 脚本要求所有 key 在同一槽,否则报 CROSSSLOT 错误;
- 数据倾斜:哈希对 key 分布并不完全均匀,热点 key 集中在某个槽会造成单节点热点,需配合热 key 打散治理;
- 缩容同理:下线节点前先把其持有的槽迁移到其他节点,槽清空后才能安全下线,否则会丢数据;
- 迁移节奏控制:生产上分批小流量迁移并观察延迟指标,避免一次性搬移过多槽造成抖动。
四、常用运维命令
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 ... --cluster-replicas 1
redis-cli --cluster reshard 127.0.0.1:7000 # 交互式迁移槽
redis-cli --cluster info 127.0.0.1:7000 # 查看槽分配与节点状态
常见追问 / 记忆点
- 追问:为什么是 16384 而不是更大?答:槽位信息要放进节点间心跳包,16384 在扩展性与消息开销之间取得平衡。
- 追问:Cluster 能用 mget 跨槽吗?答:不能直接跨槽,需拆分请求或用哈希标签把相关 key 归入同槽。
- 追问:迁移槽时旧节点还能提供服务吗?答:能,正在迁移的槽进入双写引导状态,通过 ASK 重定向保证读写不中断。
- 记忆点:CRC16 算槽、槽归节点、MOVED 是确定搬迁、ASK 是迁移中临时引导。