Redis Cluster 的槽位机制是怎么工作的?
简化版
Redis Cluster 把 key 映射到 16384 个哈希槽,每个主节点负责一部分槽位,从而实现数据分片。客户端根据 key 计算槽位并访问对应节点;如果访问错节点,会收到 MOVED 或 ASK 重定向。
详细版
Redis Cluster 的核心点:
- 集群固定有 16384 个 hash slots;
- 每个 key 通过 CRC16 计算后映射到某个槽;
- 每个主节点负责一段槽位;
- 主节点可以配置从节点做故障转移;
- 迁移槽位时可以把槽从一个节点移动到另一个节点;
- 多 key 操作通常要求 key 在同一个槽位。
为了让多个 key 落到同一槽,可以使用 hash tag:
user:{1001}:profile
user:{1001}:orders
花括号中的 1001 会作为计算槽位的部分,因此两个 key 会落在同一个槽。
完整版教学
一、Cluster 解决的是水平分片
主从 + Sentinel 主要解决高可用,但单主节点仍然承载全部数据和写流量。Redis Cluster 把数据分散到多个主节点上,让容量和吞吐可以横向扩展。
它不是按节点数直接对 key 取模,而是引入固定数量的哈希槽。这样扩容、缩容时迁移的是槽位,而不是重新打散所有 key。
如果直接按节点数取模,3 个节点扩到 4 个节点时,大量 key 的映射结果都会变化,迁移成本很高。Cluster 固定 16384 个槽,key 先映射到槽,槽再分配给节点;扩容时只需要把部分槽迁到新节点。这个设计把“key 到节点”的变化收敛为“槽到节点”的变化。
key -> slot -> node
user:1 -> slot 3200 -> node A
user:2 -> slot 11800 -> node C
二、16384 个槽怎么映射 key
Redis Cluster 对 key 计算 CRC16,然后对 16384 取模,得到槽号。集群中每个主节点负责一部分槽。
例如:
key -> slot 5000 -> node A
key -> slot 12000 -> node B
客户端如果知道槽位分布,就可以直接把命令发给正确节点。
公式可以简化写成:
slot = CRC16(key) % 16384
比如 3 个主节点可以大致分配为:A 负责 0-5460,B 负责 5461-10922,C 负责 10923-16383。真实环境不要求连续均分,但必须所有槽都有负责的主节点,否则集群会出现槽未覆盖的问题,相关 key 无法服务。
| 层级 | 职责 |
|---|---|
| key | 业务访问对象 |
| slot | 固定 16384 个逻辑分片 |
| master node | 负责一批 slot |
| replica node | 复制 master,故障时可提升 |
记忆钩子:Redis Cluster 不是 key 直接找机器,而是 key 先找槽,槽再找机器。
三、MOVED 和 ASK 是什么
如果客户端把命令发错节点,节点会返回 MOVED,告诉客户端这个槽现在属于哪个节点。客户端更新槽位缓存后再请求正确节点。
ASK 常见于槽位迁移过程中,表示这个 key 临时在另一个节点上,需要客户端临时去目标节点询问。MOVED 更像永久重定向,ASK 更像迁移中的临时重定向。
MOVED 通常意味着客户端的槽位表过期了,应刷新本地缓存;ASK 则发生在迁移期间,客户端需要先向目标节点发送 ASKING,再执行命令,但不应因此永久改槽位归属。面试里把这两个区分清楚,可以体现你知道扩缩容迁移过程,而不是只背“会重定向”。
四、多 key 操作为什么受限制
Cluster 下不同 key 可能在不同节点。像 MGET a b、集合交集、Lua 脚本涉及多个 key 时,如果 key 不在同一个槽,单个节点无法原子处理所有数据。
这时可以使用 hash tag,让相关 key 落到同一槽:
cart:{u100}:items
cart:{u100}:total
但 hash tag 不能滥用。如果大量 key 都用同一个 tag,会造成单槽热点,破坏分片均衡。
例如下面两个 key 会按 {u100} 计算槽位,因此可以落到同一槽:
cart:{u100}:items
cart:{u100}:coupon
但如果所有订单 key 都写成 order:{all}:1、order:{all}:2,它们都会进入同一槽,Cluster 分片能力基本被废掉。hash tag 适合把确实需要原子多 key 操作的一小组 key 放到一起,不适合把全业务压到一个 tag。
五、Cluster 的高可用边界
Cluster 中每个主节点可以有从节点。主节点故障时,集群可以把对应从节点提升为主节点,继续负责这些槽。
但如果某个主节点及其从节点都不可用,对应槽位无法服务,集群可用性就会受影响。所以生产要合理部署主从、机架和可用区分布。
还要注意 Cluster 不是强一致复制。主从复制仍可能有延迟,主节点刚写入但未复制到从节点时故障,可能存在少量数据丢失风险。Cluster 提供分片和自动故障转移能力,但业务仍要根据数据重要性设计幂等、补偿和持久化方案。
六、扩容迁移时发生什么
扩容时,新节点加入集群后通常会从旧节点迁移一部分槽。迁移过程中,一个槽里的 key 会逐步移动,客户端可能收到 ASK 临时重定向;迁移完成后,槽归属改变,客户端收到 MOVED 并更新槽位缓存。迁移单位是槽,而不是每次都重新计算所有 key 到节点的映射。
扩容前:
node A: slots 0-8000
node B: slots 8001-16383
扩容后:
node C 接收 A/B 的部分 slots
客户端刷新 slot -> node 映射
七、常见误区与追问
- 误区:Redis Cluster 按节点数对 key 取模。 Cluster 固定 16384 个槽,key 映射到槽,槽再分配给节点。
- 误区:加节点后热点 key 会自动分散。 单个 key 仍属于一个槽和一个主节点,热点 key 需要本地缓存、副本 key 或业务拆分治理。
- 误区:hash tag 可以随便用。 hash tag 会让相关 key 落同槽,滥用会制造单槽热点,破坏均衡。
- 误区:MOVED 和 ASK 是一回事。 MOVED 表示槽归属已变化,需要更新缓存;ASK 是迁移中的临时访问。
- 追问:为什么多 key 操作要求同槽? 因为 Redis 单节点只能原子处理自己拥有的数据,跨节点多 key 原子性和一致性无法由单个节点保证。
- 追问:Cluster 能替代 Sentinel 吗? Cluster 自带分片和主从故障转移能力,Sentinel 主要管理非 Cluster 主从;两者解决模型不同,不能简单等同。
八、加强记忆
Redis Cluster 的核心是 16384 个哈希槽:key 通过 CRC16(key) % 16384 找槽,槽再归属某个主节点。客户端缓存槽位表,访问错节点会收到 MOVED,槽迁移中可能收到 ASK。多 key 原子操作要求同槽,可以用 hash tag 控制相关 key,但不能滥用到制造热点。Cluster 解决分片扩容和一定高可用,不会自动消除单 key 热点,也不等于强一致存储。