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

Redis Cluster 返回 MOVED 时客户端要做什么

来源:17golang原创

时间:2026-11-11 20:50:20 415浏览 收藏

Redis Cluster 返回 MOVED 时,客户端不要把它当成普通业务失败,也不要在单节点客户端外层无限重试。这个响应表示:当前节点收到了请求,但 key 对应的哈希槽由另一个节点负责;响应中已经给出了槽位和目标节点地址。正确做法是使用能理解 Redis Cluster 拓扑的客户端,让它把请求重新发给目标节点,并更新本地槽位映射。

命令行临时排查用 redis-cli -c;应用接入用集群客户端;客户端收到 MOVED 后应更新或刷新 slot 到节点的映射。只会连接一个固定节点的普通客户端,无法可靠承担 Redis Cluster 的路由工作。

先读懂 MOVED 返回的三段信息

典型响应类似 MOVED 12182 127.0.0.1:6463。第一段是错误类型,第二段是 key 所在的哈希槽编号,第三段是当前负责该槽的节点地址。Redis Cluster 使用 16384 个哈希槽把 key 空间分给多个主节点;节点不会替客户端代理请求,所以客户端需要根据这个信息改连目标节点。

因此,MOVED 通常说明“请求发到了不负责这个槽的节点”,不等同于目标节点宕机,也不等同于数据不存在。集群拓扑变化、启动时连接了不合适的种子节点,或者客户端保存的槽位表已经过期,都可能让第一次请求撞上重定向。

Redis Cluster 客户端、MOVED 响应、哈希槽和目标节点的静态路由关系说明图
图1:MOVED 返回的槽位与目标地址关系说明图,帮助理解客户端为什么需要重新选择节点;这是静态结构说明图,不是运行截图。

命令行排查直接使用 redis-cli -c

如果只是人工确认某个 key 能否通过集群路由访问,使用带 -c 的 redis-cli。这个选项让命令行客户端跟随 MOVED 重定向,而不是把错误原样停在当前节点。

# -c 表示启用 Redis Cluster 重定向跟随能力
redis-cli -c -h 127.0.0.1 -p 7000

# 让客户端按 key 的槽位找到负责节点
GET user:1001

# 退出命令行客户端
QUIT

这里的 7000 只是连接入口示例,不代表所有集群都使用这个端口。若不加 -c,直接连到某个节点后执行涉及其他槽位的命令,看到 MOVED 是预期行为;加上 -c 后,客户端会根据重定向继续访问目标节点。

应用连接必须选择集群客户端

应用代码不要把单实例客户端对象改个连接地址就当成集群接入。集群客户端通常负责三件事:启动时获取或建立槽位到节点的拓扑、按 key 计算目标槽位并选择连接、收到 MOVED 后修正本地映射并重新发送请求。不同语言的库名称不同,但选型标准是一致的:文档明确支持 Redis Cluster,而不是只支持单节点连接。

如果当前库只会把 MOVED 当成普通错误返回,外层可以记录错误并触发受控的拓扑刷新,但不应自己写一个无限递归重试器。应优先换用该语言的集群客户端或启用它的 cluster 模式,并设置有限的重定向次数、连接超时和错误日志,避免拓扑异常时放大请求。

redis-cli -c、普通单节点客户端、集群客户端与槽位映射之间的静态选择关系图
图2:命令行与应用客户端的集群能力边界说明图,展示重定向跟随和槽位映射的职责;这是静态说明图,不是终端输出。

收到 MOVED 后要更新哪一部分状态

客户端至少需要知道“哪个 slot 由哪个 endpoint:port 负责”。Redis Cluster 规范允许客户端只更新被移动的槽位,也允许在收到 MOVED 后重新获取完整拓扑;后者在一次故障切换或重分片可能同时影响很多槽位时更稳妥。客户端如何实现由库决定,接入方重点看它是否支持拓扑刷新和重定向上限。

启动配置通常提供多个种子节点,而不是把单个节点当成永久路由中心。种子节点用于取得集群布局;稳定运行后,集群客户端会按槽位直接连接相应节点,减少每次都先撞到错误节点的机会。若响应中的地址是容器内地址、内网地址或客户端不可达地址,还要检查 Redis 节点对外公布的 endpoint 配置,这属于地址可达性问题,不应靠重复重试掩盖。

MOVED :

这段是响应格式,不是可执行命令。排障日志应保留 slot、目标地址、客户端名称和重定向次数,但不要把访问密码、完整连接串或其他凭据写入日志。

别把 MOVED、ASK 和 CROSSSLOT 混为一谈

返回类型含义客户端动作
MOVED槽位由另一个节点负责,响应给出目标地址。重新发送,并更新或刷新槽位映射。
ASK槽位正在迁移,目标节点可能已经有这个 key。按集群客户端协议临时发送 ASKING 后再发一次命令,不把它永久写入槽位表。
CROSSSLOT一次多 key 命令涉及不同哈希槽。调整 key 设计或使用 hash tag,让相关 key 落在同一槽位。

尤其不要用处理 MOVED 的方式修复 CROSSSLOT。后者是命令涉及的 key 分布问题;如果业务确实需要多 key 原子操作,应从 key 命名和 hash tag 设计入手,而不是继续刷新拓扑。

按场景选择方案

场景推荐做法不要做什么
人工确认 key 路由redis-cli -c 连接任意可达节点。把一次 MOVED 误判成 Redis 服务不可用。
应用正式接入选择明确支持 Redis Cluster 的客户端,配置多个种子节点。用单节点客户端在业务层无限重试。
频繁出现 MOVED查看客户端拓扑刷新、重定向次数和节点公布地址。只增加重试次数,不检查槽位表和 endpoint 可达性。
出现 ASK 或 CROSSSLOT分别按迁移协议或 key 槽位设计处理。把所有集群错误都当成 MOVED。

最后可以把判断压缩成一句话:MOVED 是 Redis Cluster 告诉客户端“去另一个节点找这个槽位”,客户端的职责是理解重定向、维护拓扑并受控重发;应用接入的关键不是手写更多重试,而是选对集群客户端。

相关问题

为什么连接了 Redis Cluster 还会偶尔看到 MOVED?

首次连接、拓扑刚发生变化或客户端槽位映射过期时,都可能先收到一次 MOVED。集群客户端应能据此更新映射;如果次数持续升高,再检查拓扑刷新和节点公布地址。

redis-cli 不加 -c 能不能访问集群?

可以连接节点并执行恰好由该节点负责槽位的请求,但遇到其他槽位时会直接看到 MOVED。人工使用时加 -c 更合适。

能不能在业务代码里捕获 MOVED 后自己拼地址重试?

不建议把完整集群路由逻辑长期放在业务层。使用具备拓扑发现、槽位映射、MOVED/ASK 处理和重试上限的集群客户端更容易维护。

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