Redis Cluster 是 Redis 官方提供的分布式解决方案,通过分片(sharding)将数据分散到多个节点上。在集群模式下,客户端访问某个 key 时,可能会被重定向到另一个节点。理解 MOVED 和 ASK 这两种重定向机制的差异,是掌握 Redis Cluster 工作原理的关键,也是面试中的高频考点。本文将从原理、触发场景、客户端处理方式等角度,深入剖析两者的区别。
一、背景:Redis Cluster 的槽位机制
在深入 MOVED 和 ASK 之前,有必要先回顾 Redis Cluster 的数据分布基础。
Redis Cluster 将整个键空间划分为 16384 个哈希槽(slot),每个 key 通过以下公式确定所属槽位:
slot = CRC16(key) mod 16384
集群中的每个主节点负责一部分槽位。客户端在访问某个 key 时,需要先计算出它对应的槽位,然后将请求发送到负责该槽位的节点。如果客户端发送到了错误的节点,节点就会返回重定向信息,告诉客户端应该去哪个节点访问。
正是这种“客户端可能不知道最新槽位映射”的现实,催生了 MOVED 和 ASK 两种重定向机制。
二、MOVED 重定向:槽位已永久迁移
2.1 触发场景
MOVED 错误表示:该 key 对应的槽位已经永久性地迁移到了另一个节点。客户端应该更新本地的槽位映射缓存,并将后续所有属于该槽位的请求都发往新节点。
典型场景包括:
- 集群扩容时,将部分槽位从旧节点迁移到新节点;
- 集群缩容时,将某个节点的槽位全部迁出;
- 手动执行
CLUSTER ADDSLOTS/CLUSTER DELSLOTS调整槽位归属; - 故障转移后,从节点晋升为主节点,接管原主节点的槽位。
2.2 返回格式
当客户端向错误节点发送请求时,节点返回:
-MOVED 3999 127.0.0.1:6381
其中 3999 是 key 所属的槽位编号,127.0.0.1:6381 是当前负责该槽位的节点地址。
2.3 客户端处理方式
客户端收到 MOVED 后,应当:
- 更新本地槽位映射表,将槽位 3999 指向新节点;
- 重新向新节点发送请求;
- 后续所有属于该槽位的请求,直接发往新节点,不再走错。
MOVED 的本质是一次“永久性纠正”,客户端应将其视为槽位归属的权威信息。
三、ASK 重定向:槽位正在迁移中
3.1 触发场景
ASK 错误表示:该 key 对应的槽位正在迁移过程中。此时槽位在源节点和目标节点之间处于中间状态,源节点仍然负责该槽位,但该 key 可能已经被迁移到了目标节点。
具体来说,当源节点正在迁移槽位 N 时:
- 如果客户端请求的 key 仍然存在于源节点,源节点正常处理;
- 如果该 key 已经被迁移到目标节点,源节点会返回 ASK 错误,指引客户端去目标节点获取。
3.2 返回格式
-ASK 3999 127.0.0.1:6381
格式与 MOVED 类似,但语义完全不同。
3.3 客户端处理方式
客户端收到 ASK 后,应当:
- 不更新本地槽位映射表(因为槽位归属尚未最终确定);
- 向目标节点发送
ASKING命令,然后再发送原请求; - 目标节点只有在收到
ASKING命令后,才会处理属于正在迁移槽位的请求。
这里的关键是 ASKING 命令。目标节点在迁移过程中,对于尚未正式接管的槽位,默认会拒绝请求并返回 MOVED。只有客户端先发送 ASKING,目标节点才会“破例”处理这一次请求。
四、核心区别对比
| 维度 | MOVED | ASK |
|---|---|---|
| 语义 | 槽位已永久迁移 | 槽位正在迁移中 |
| 是否更新客户端缓存 | 是,必须更新槽位映射 | 否,不能更新 |
| 是否需要 ASKING 命令 | 不需要 | 需要,先发 ASKING |
| 重定向性质 | 永久性 | 临时性、一次性 |
| 触发时机 | 槽位迁移完成、故障转移后 | 槽位迁移进行中 |
| 后续请求 | 直接发往新节点 | 仍发往源节点,除非再次收到 ASK |
可以用一句话概括:MOVED 是“搬家已完成,以后都去新地址”;ASK 是“东西正在搬,这一件你先去新地址取,但别改地址簿”。
五、为什么需要 ASK 这种“临时重定向”?
如果不引入 ASK,迁移过程中会出现数据不一致或请求失败的问题。
假设槽位 3999 正在从节点 A 迁移到节点 B。迁移是逐个 key 进行的,在某个时刻,key1 已经迁到 B,key2 还在 A。如果客户端请求 key1:
- 若 A 直接返回 MOVED,客户端会更新缓存,认为整个槽位 3999 都归 B 管;
- 但此时 key2 还在 A,客户端去 B 请求 key2 会失败。
因此,A 对已迁移的 key 返回 ASK,让客户端临时去 B 取,但不改变槽位归属认知;对未迁移的 key 正常处理。这样既保证了迁移期间请求的正确性,又避免了客户端过早更新映射。
六、面试常见追问
追问 1:客户端收到 ASK 后,如果目标节点又返回 MOVED 怎么办?
这说明迁移已经完成,目标节点正式接管了该槽位。客户端应更新本地映射,后续直接访问目标节点。
追问 2:MOVED 和 ASK 会不会同时出现?
不会针对同一个请求同时出现。节点根据当前 key 的状态和槽位迁移状态,决定返回哪一种。
追问 3:集群模式下,客户端如何避免频繁重定向?
客户端应缓存槽位映射表,并在收到 MOVED 后及时更新。同时可以订阅 CLUSTER SLOTS 或使用 MOVED 反馈来刷新拓扑。成熟的客户端(如 Jedis、Lettuce、redis-py-cluster)都内置了这些机制。
追问 4:ASKING 命令的作用范围是什么?
ASKING 只对紧接着的下一条命令生效,是一次性的。它不会改变节点的槽位归属状态。
七、总结
MOVED 和 ASK 都是 Redis Cluster 用于引导客户端正确访问数据的重定向机制,但二者语义截然不同:
- MOVED 表示槽位归属已永久变更,客户端应更新缓存并改变后续路由;
- ASK 表示槽位正在迁移,客户端应临时访问目标节点,但不得更新缓存。
理解这两者的区别,不仅有助于通过面试,更能帮助我们在实际开发中正确配置客户端、排查集群访问异常。在集群运维中,槽位迁移是常态,而 MOVED 和 ASK 正是保证迁移期间服务可用的关键设计。掌握它们,才算真正迈入了 Redis Cluster 的大门。
未经允许不得转载:任鹏个人博客 » Redis Cluster 的 MOVED 和 ASK 重定向有什么区别

