必须使用redis-cli -c启用集群模式才能解析MOVED响应并自动跳转;Python需用rediscluster.RedisCluster而非redis.Redis;Java客户端须区分MOVED与ASK响应,ASK前必须发ASKING命令。

redis-cli没加-c参数导致MOVED原样返回
普通模式的redis-cli根本不解析MOVED响应,只把错误原封不动抛给你。这不是集群问题,是客户端压根没启用路由能力。
- 必须用
redis-cli -c -h [host] -p [port]启动,连接后执行命令会看到类似Redirected to slot [12345] located at 192.168.1.5:6379的提示 - 如果已连上但忘了
-c,退出重连,别试图在当前会话里“补救” -
-c不会改变服务端行为,只是让客户端自己做跳转——服务端从不转发请求
Python用错客户端类:redis.Redis vs rediscluster.RedisCluster
redis.Redis是单点客户端,遇到MOVED直接抛MovedError异常;rediscluster.RedisCluster才是集群版,内置Slot映射缓存和自动重试逻辑。
- 初始化时必须传
startup_nodes列表(不能只写一个节点),否则无法获取完整拓扑 - 务必加
skip_full_coverage_check=True,否则某个从节点宕机就初始化失败 - 写操作默认只发给master,如果刚
set()完立刻get()失败,先检查key是否含{}——user:{1001}:profile和user:1001:profile算出来的slot完全不同
Java客户端混淆MOVED和ASK响应
MOVED表示槽已永久归属新节点,要更新本地Slot映射;ASK只在迁移中临时生效,发过去前必须先发ASKING命令,且不能改缓存。
- 用
JedisCluster时,maxRedirections建议设为3——太小(如1)会卡在正常迁移中途,太大(如16)可能陷入循环 - 收到
ASK 1234 10.0.1.6:6379,不能直接更新slot 1234 → node 10.0.1.6,而要在同一连接上先执行ASKING,再发原命令 - 判断响应类型必须严格用前缀匹配:
if (err.startsWith("ASK ")),别用contains("ASK"),否则CLUSTERDOWN也可能被误判
客户端拓扑缓存过期却没刷新
Slot映射表不是永久有效的。节点下线、扩容、failover后,旧缓存会导致请求持续打到错误节点,反复触发MOVED。
- 不要在每次
MOVED后都同步调用refreshNodes()——这可能引发嵌套跳转,尤其在集群状态未稳时 - 推荐策略:连续2次
MOVED指向同一错误地址,再触发一次CLUSTER SLOTS拉取 - Redisson需确认版本≥3.28.0,并设置
setRefreshPeriod(30000)和setRetryAttempts(3)
实际部署中最容易被忽略的是ASK场景下的ASKING前置命令——漏掉它,目标节点直接拒收,接着报MOVED或ERR,形成二次跳转。这个细节不写进日志,也不报明确错误,只能靠抓包或调试日志定位。











