MOVED 与 ASK 是什么
集群用两套重定向机制告诉客户端「这个键不在我这」:MOVED 表示槽已经稳定归属于另一个节点,客户端应更新本地路由表并后续都直接发往新节点;ASK 表示槽正在迁移过程中,只有当前这一次请求需要改道到目标节点,并且目标节点要求客户端先发一条 ASKING 命令才处理。区分二者的关键是「永久」与「临时」:MOVED 改路由表,ASK 不改。
基本信息
| MOVED 格式 | MOVED <slot> <ip>:<port> |
|---|---|
| ASK 格式 | ASK <slot> <ip>:<port> |
| ASKING | 发往目标节点前的一次性开关,仅对紧随其后的命令生效 |
| 客户端要求 | 必须同时实现两种重定向处理,否则简单命令也可能失败 |
| 调试参数 | redis-cli -c 打开自动跟随模式 |
典型使用场景
- 扩容迁移期间:槽从旧节点迁往新节点,迁移中的键由 ASK 临时改道,已迁完的键由 MOVED 永久改道
- 故障切换后:新主节点接管的槽对旧连接返回 MOVED,客户端据此刷新路由
- 客户端库自检:确认所用客户端是否支持集群,最直接的方式就是观察它能否正确处理这两类返回
- 排查「服务正常但请求失败」:大量 MOVED 说明客户端没跟上拓扑变化,而节点本身工作正常
- 监控迁移进度:观察 ASK 出现频率,长期不衰减说明迁移任务没有正常收尾
观察重定向
观察重定向
redis-cli -p 7000 GET user:1001 # 未开 -c,槽归他人时返回 MOVED
redis-cli -p 7000 -c GET user:1001 # 开启跟随,客户端自动改道
# 手工模拟 ASK 流程:先 ASKING 再发命令
redis-cli -p 7001 ASKING
redis-cli -p 7001 GET user:1001
redis-cli -p 7000 CLUSTER COUNTKEYSINSLOT 1234 # 该槽还有多少键未迁走两种重定向对照
| 维度 | MOVED | ASK |
|---|---|---|
| 触发条件 | 槽已归属其他节点 | 槽处于迁移中且键仍在源节点 |
| 语义 | 永久重定向 | 仅本次请求的临时改道 |
| 客户端动作 | 更新路由表,后续请求直达新节点 | 本次改道,不更新路由表 |
| 目标节点要求 | 正常处理即可 | 必须先收到 ASKING 才接受该键 |
| 出现时机 | 拓扑变化之后 | 仅出现在迁移窗口内 |
为什么 ASK 需要 ASKING:迁移中的槽在两个节点上都可能持有该键的数据,源节点为了避免把请求误转到尚未收到数据的节点,要求客户端显式声明「这条命令按迁移语义处理」。这也是自研客户端最容易实现错的地方,通常表现为个别键在迁移期间偶发返回 nil。
客户端如果不处理重定向,故障表现极具误导性:命令级错误里都是 MOVED 或 ASK,看起来像服务端故障,实际服务端完全正常。排查集群问题时应先把客户端是否开启集群模式作为第一个确认项。