登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis Cluster 重定向为什么出现 MOVED 和 ASK

来源:17golang原创

时间:2026-11-02 08:02:31 490浏览 收藏

Redis Cluster 出现 MOVED,通常表示请求发给了不负责该槽位的节点,客户端应按响应中的目标重新路由,并更新槽位缓存。ASK 则表示槽迁移期间的一次临时转向:到目标节点发送 ASKING,再在同一连接上重发原命令,不能仅凭 ASK 把整个槽的归属改成目标节点。

两者都是集群路由协议的一部分。真正需要排查的是:客户端是否能处理重定向、目标地址是否可达,以及迁移期间是否正确保持连接上下文。下面以单键读取为例讲解,不把协议说明写成未经证实的线上事故。

官方地址:https://redis.io/

先看失败发生在第一次连接还是迁移期间

同样是“读不到数据”,发生时机能缩小排查范围。第一次用普通客户端直连任意节点就收到 MOVED,应先检查是否误用了单机连接模式;已有应用在扩容或槽迁移后才出现 ASK,应查迁移窗口与客户端的临时重定向支持。收到重定向后紧接着超时,则要把“路由响应”和“连接目标失败”分成两条线索。

复盘时按实际记录排列:应用开始报错的时间、连接配置变更、集群调整记录、首次重定向、客户端后续动作。不要把所有 MOVED 都归因于扩容:初始连接到错误节点、客户端槽缓存过期,也会遇到它。

日志至少保留错误类型、槽号、原节点、目标端点和最终错误;业务键可能含敏感信息,按需要脱敏。只有第一次路由响应而没有后续结果,不能判断请求最终是否成功。

MOVED 指向槽位归属,ASK 指向迁移中的单次请求

Redis Cluster 用槽位组织键的分布。客户端通常维护槽位缓存,据此选择节点。MOVED 响应给出槽号和应访问的目标;所谓“永久重定向”指后续路由应跟随当前归属,不是承诺这个槽以后永远不会再次迁移。客户端可以更新相关槽,也可按实现刷新完整拓扑。

比较项MOVEDASK
表达的含义该槽应访问另一节点本次命令临时访问迁移目标
目标上的准备命令正常路由无需额外 ASKING先发 ASKING,再发原命令
槽位缓存更新或刷新不能仅凭该响应改写归属
后续独立请求按更新后的路由处理继续使用原槽路由,必要时再次处理重定向

在传统逐键迁移模式下,源节点为该槽标记 MIGRATING,目标节点标记 IMPORTING。源节点仍有被访问的单键时可以处理;源节点没有该键时可能返回 ASK。这也涵盖新键尚未存在的情况,因此 ASK 不能被解释成“这个键已经迁移成功”的证明。此处只解释单键请求,不把它推广到多键命令。

槽位缓存、槽号、源节点和目标节点与两类重定向的静态关联
图1:静态结构说明图。MOVED 与槽位缓存更新有关,ASK 与迁移目标有关;节点间的连线用于解释路由对象,不表示操作顺序或实时迁移状态。

用只读命令核对槽号、拓扑和目标端点

下面的主机名是示例占位符,替换为自己的测试集群入口;命令未在本文中实际执行。鉴权和 TLS 参数沿用所在环境的配置。先用同一键比较普通模式与集群模式,避免一次换键、换端点、换配置后无法归因。

# 普通模式不自动跟随集群重定向,可观察入口节点的原始响应
redis-cli -h seed.example.test -p 6379 GET 'probe:{routing}:sample'

# -c 开启集群模式,自动处理 MOVED 与 ASK
redis-cli -c -h seed.example.test -p 6379 GET 'probe:{routing}:sample'

# 计算这个键的槽号,不要求键已经存在,也不会创建它
redis-cli -h seed.example.test -p 6379 CLUSTER KEYSLOT 'probe:{routing}:sample'

# Redis 7.0 及以上可读取分片和槽位映射,旧版本按支持情况用 CLUSTER SLOTS
redis-cli -h seed.example.test -p 6379 CLUSTER SHARDS

观察结果应这样解释:若入口不负责该槽,普通模式可能显示重定向;集群模式若正确跟随,会得到 GET 的正常返回,包括键不存在时的空值。空值只能说明最终查询没有读到值,不能证明它之前存在,更不能用来宣布数据丢失。

CLUSTER KEYSLOT 给出键对应的槽号,帮助与报错中的槽号对照。CLUSTER SHARDS 返回槽段及节点信息,应关注 endpoint、端口、角色和健康状态。不要把诊断命令返回的拓扑直接当作永久配置写死到应用。

ASKING 必须和原命令使用同一条目标连接

ASKING 设置的是目标连接上的一次性状态,不是集群全局开关。对一个普通单键命令,客户端需要独占目标连接,完成 ASKING 与原命令的相邻发送;中间不能插入健康探测或其他业务命令,也不能把连接提前交回连接池。

下面用一次 redis-cli 进程传入两条命令,说明它们共享一个连接。只在已确认收到 ASK、且目标处于相应导入状态的测试场景使用。目标端点应取自实际响应,不能凭空猜测;这不是构造迁移状态的教程。

# 同一进程、同一目标连接;两行之间不加入 PING 等其他命令
redis-cli -h target.example.test -p 6379 

ASKING 的 OK 只是接受该连接状态的应答,仍须读取后续 GET 的结果。若把 ASKING 和 GET 分成两次独立 redis-cli 调用,它们建立不同连接,第二次不会继承标记。连接池中的逻辑也一样:向池对象发两次命令,不一定使用同一条物理连接。

应用代码优先交给成熟的 Cluster 客户端处理。自行封装时,应让同一组件负责连接借出、两条命令的应答读取和连接归还;如果中途断连或结果不明,不应把可能带有残留协议状态的连接继续用于普通请求。本文不扩展到事务和流水线,它们应遵循客户端对应的集群实现规则。

连接池独占租用与ASKING标记、原命令和目标连接之间的静态关系
图2:静态结构说明图。ASKING 标记属于目标连接,原命令也必须绑定该连接;连接池的独占租用约束用于防止其他命令串入,不是执行截图。

重定向后仍失败,要修地址和客户端模式

如果 redis-cli 集群模式可读而应用仍把 MOVED 原样抛给业务层,先检查实际创建的客户端类型、部署配置是否生效,以及客户端是否配置为 Cluster 模式。仅把多个节点地址塞进一个普通连接池,并不等于具备槽位路由能力。

如果能连种子节点,却连接不了重定向目标,检查客户端所在网络能否解析目标域名、访问目标端口,并核对 TLS 设置。容器、代理或网络地址转换场景中,节点对外公布的端点可能与应用可达地址不同。修正部署中的地址发布或受支持的地址映射配置;只更换种子节点不能自动修复目标端点。

若 ASK 期间在源和目标间反复跳转,排查是否把 ASK 当 MOVED 更新了槽缓存,或在目标连接上漏发 ASKING。若拓扑仍在变化,则保留最新重定向记录交给集群运维处理,不要为了消除报错直接修改槽归属或清除迁移标记。

重试应限制重定向次数,并计入请求总超时预算。明确收到路由错误和发生网络超时不是同一语义;写请求超时后可能无法确认是否执行,重试策略必须结合业务幂等性,不能机械复制读请求策略。

恢复后记录重定向变化与后续防范

恢复判断要看最终请求:目标节点可达,Cluster 客户端能取得正常响应,迁移完成后同一批键的路由不再持续循环。记录客户端模式、拓扑刷新方式、网络修复项和迁移结束时间,便于把下一次同类现象定位到具体层。

  • 使用受控的只读探针,对照槽号与实际目标,不向生产写测试数据。
  • 保留 MOVED、ASK 和最终连接错误的分类计数,避免把正常重定向与最终失败混为一个告警。
  • 发布前确认应用网络能访问所有需要的节点端点,扩容后继续覆盖新增节点。
  • 维护客户端的有限重试、总超时和拓扑更新配置,避免每次请求都重新获取完整拓扑。

MOVED 是数据已经丢失了吗?

不是。它说明当前节点要求客户端到其他端点访问该槽。是否存在数据问题,需要结合最终查询、业务记录和集群状态另行判断。

ASK 出现后能直接把槽缓存改成目标节点吗?

不能仅凭 ASK 这样做。它针对当前重定向请求,后续独立请求继续按原路由处理,等归属更新后再接受 MOVED 或新的拓扑信息。

CROSSSLOT 也能靠跟随重定向解决吗?

不能。多键命令涉及不同槽时,应调整键设计或拆分符合语义的操作;即使在同槽内,迁移期间也可能有多键操作的额外限制。它与单键 MOVED、ASK 的路由问题要分别处理。

官方参考:Cluster 路由规范、迁移和导入状态、ASKING、CLUSTER KEYSLOT、CLUSTER SHARDS、redis-cli 参数。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>