Redis Cluster 的 MOVED 和 ASK 重定向有什么区别

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 后,应当:

  1. 更新本地槽位映射表,将槽位 3999 指向新节点;
  2. 重新向新节点发送请求
  3. 后续所有属于该槽位的请求,直接发往新节点,不再走错。

MOVED 的本质是一次“永久性纠正”,客户端应将其视为槽位归属的权威信息。

三、ASK 重定向:槽位正在迁移中

3.1 触发场景

ASK 错误表示:该 key 对应的槽位正在迁移过程中。此时槽位在源节点和目标节点之间处于中间状态,源节点仍然负责该槽位,但该 key 可能已经被迁移到了目标节点。

具体来说,当源节点正在迁移槽位 N 时:

  • 如果客户端请求的 key 仍然存在于源节点,源节点正常处理;
  • 如果该 key 已经被迁移到目标节点,源节点会返回 ASK 错误,指引客户端去目标节点获取。

3.2 返回格式

-ASK 3999 127.0.0.1:6381

格式与 MOVED 类似,但语义完全不同。

3.3 客户端处理方式

客户端收到 ASK 后,应当:

  1. 不更新本地槽位映射表(因为槽位归属尚未最终确定);
  2. 向目标节点发送 ASKING 命令,然后再发送原请求;
  3. 目标节点只有在收到 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 重定向有什么区别

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏