Redis Cluster 迁移 slot 时客户端为什么会收到 MOVED
来源:17golang原创
时间:2026-09-07 14:54:28 157浏览 收藏
Redis Cluster 迁移 slot 时看到 -MOVED 6380 10.0.0.12:6379,通常不是数据丢失,而是客户端连接的节点已经不是这个 slot 的当前 owner。关键在于:稳定状态下的 MOVED 表示应永久更新路由;迁移中间态的 ASK 只表示当前这一次命令临时去目标节点。把两者混为一谈,才会让重试和拓扑缓存越修越乱。
先按 key 算出 slot,再看该 slot 的真实归属;收到 MOVED 就刷新 slot 映射,收到 ASK 则只对当前命令发送 ASKING,不要提前把整个 slot 表改到目标节点。
- Redis Cluster 将 key 映射到 0~16383 的 hash slot,客户端通常缓存 slot 到节点的关系。
- MOVED 是稳定归属变化或访问了错误节点的永久重定向;ASK 是迁移期间的单次重定向。
- 客户端应支持 Cluster 模式,能处理 MOVED、ASK、ASKING、TRYAGAIN 和多 key 跨 slot 边界。
- 排查时同时看
CLUSTER SLOTS或CLUSTER SHARDS、CLUSTER NODES与客户端拓扑刷新日志。
为什么旧连接会拿到 MOVED
Redis Cluster 的 key 先经过 CRC16(key) mod 16384 得到 slot。集群稳定时,一个 slot 由一个主节点负责。客户端为了减少每次请求的路由成本,会在内存里保存一份 slot 表,但这份表可能因为 reshard、故障转移或刚启动而落后。
# 用集群模式连接,让客户端能够跟随 MOVED/ASK
redis-cli -c -h 10.0.0.11 -p 6379
# 查看业务 key 映射到哪个 slot
redis-cli -c -h 10.0.0.11 -p 6379 CLUSTER KEYSLOT user:{42}:profile
# 查看 slot 到节点的当前映射
redis-cli -h 10.0.0.11 -p 6379 CLUSTER SLOTS
假设客户端仍把 slot 6380 指向 Node-A,而集群配置已经把它交给 Node-B。请求先到 Node-A,Node-A 返回 MOVED 和 Node-B 的地址。正确的动作是更新本地 slot 表,让后续请求直接去 Node-B;只重试当前请求而不更新映射,会让每个请求都多一次往返。

迁移中间态为什么先出现 ASK
reshard 并不是瞬间把所有 key 从源节点搬走。典型过程是:目标节点先把 slot 标记为 IMPORTING,源节点再标记为 MIGRATING,随后用 CLUSTER GETKEYSINSLOT 找出 key 并迁移。此时同一个 slot 的旧 key 可能仍在源节点,新 key 则应该在目标节点创建。
因此源节点遇到不存在的 key 时返回 ASK,告诉客户端“这一个命令去目标节点试试”。客户端连接目标节点后先发送一次 ASKING,再发送原命令;它不能因为一次 ASK 就把 slot 永久改指向目标节点,因为其他 key 仍可能留在源节点。

迁移结束后,协调方会向相关节点发送 CLUSTER SETSLOT slot NODE target-node-id,让目标节点成为正式 owner。此后再访问旧节点,收到的就是表示永久归属变化的 MOVED。也就是说,ASK 关注“这一次命令”,MOVED 关注“以后应该找谁”。
客户端该刷新什么,哪些错误不能盲目重试
新客户端可以使用 CLUSTER SHARDS 获取分片与节点信息;历史客户端常用 CLUSTER SLOTS。Redis 文档已将 CLUSTER SLOTS 标为 7.0 起 deprecated,新实现应确认客户端库是否支持 SHARDS,但这不等于旧集群会停止返回 MOVED。
| 返回 | 含义 | 客户端动作 |
|---|---|---|
| MOVED | slot 的正式 owner 在另一节点,或当前节点不是 owner | 重试并刷新该 slot,必要时重新拉取完整拓扑 |
| ASK | slot 正在迁移,目标节点暂时接收当前命令 | 只重试当前命令,先发 ASKING,不更新永久映射 |
| TRYAGAIN | 多 key 命令遇到迁移中的部分状态 | 短暂退避后重试,检查是否把多 key 操作拆到了不同 slot |
排查时先记录完整错误行、slot、目标地址和客户端库版本,再在任意节点执行 CLUSTER NODES。输出中的 slot->-node-id 表示 migrating,slot- 表示 importing。若 MOVED 长时间重复出现,重点检查客户端是否以 Cluster 模式初始化、是否禁用了拓扑刷新、容器或代理是否把节点地址改写错,以及是否存在旧连接池缓存。
多 key 命令还要单独看 hash tag。把相关 key 写成 order:{100}:items 和 order:{100}:total,可以让相同花括号内容参与 slot 计算;但这只是让 key 进入同一 slot,不会替客户端处理迁移中的临时状态。
相关问题
收到 MOVED 后只重试当前请求可以吗?
可以暂时完成当前请求,但不应停在这里。客户端还要更新 slot 表,否则下一次仍访问旧节点,MOVED 会变成固定的额外往返。
ASK 后为什么必须发送 ASKING?
目标节点处于 IMPORTING 状态时,不带 ASKING 的普通请求会被拒绝并再次返回 MOVED。ASKING 是只对下一条命令生效的一次性许可。
redis-cli 为什么看不到 MOVED?
使用 redis-cli -c 后,命令行客户端会代为处理集群重定向。要观察原始返回,可连接单个节点并关闭 Cluster 模式,再结合 CLUSTER KEYSLOT 和 CLUSTER NODES 判断路由。
记住一条判断线就够了:归属已经确定变化,用 MOVED 更新拓扑;归属正在搬迁,用 ASK 只转发当前命令。把客户端初始化、重试策略和 slot 表刷新放在同一个 Cluster 语义里,迁移期间的日志就不再是“随机报错”,而是能解释的状态信号。
-
117 收藏
-
426 收藏
-
171 收藏
-
113 收藏
-
195 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习