根本原因是客户端未及时刷新集群拓扑,导致请求发往已下线或未接管槽位的节点;具体表现为拓扑未刷新、重定向被忽略、连接池含过期地址,且 cluster-announce-ip 配置错误(如 127.0.0.1)是最高频根因。

扩缩容期间请求超时,根本不是网络或配置漂移导致的,而是客户端还在往已下线或尚未接管槽位的节点发请求——拓扑没刷新、重定向被忽略、连接池里塞着过期地址,三者叠加,超时就是必然结果。
redis-cli -c cluster nodes 输出含 127.0.0.1 或 0.0.0.0 就别往下查了
这是最常被跳过的根因:客户端拿到的节点地址本身就是错的,后续所有超时都只是表象。执行 redis-cli -c -h 192.168.1.100 -p 6379 cluster nodes,如果任意一行 IP 是 127.0.0.1 或 0.0.0.0,那你的应用必然在重定向时连本地,然后卡死超时。
-
cluster-announce-ip必须设为该机器真实对外 IP(不能是内网 NAT 地址,也不能是容器 host 网络下的虚拟 IP) -
cluster-announce-port和cluster-announce-bus-port必须显式设置,且与实际监听端口一致 - 改完后不能只
CONFIG REWRITE或redis-cli CONFIG RELOAD——必须执行redis-cli cluster reset hard再重启进程,否则旧拓扑仍广播错误地址
Lettuce 拓扑不刷新,等于让客户端闭眼走路
Spring Boot 2.x+ 默认用 Lettuce,但它默认不自动刷新集群拓扑。主从切换或 slot 迁移后,客户端还在往旧 master 地址发请求,TCP 连接阶段就卡住,直到 spring.redis.timeout 触发——这不是命令慢,是根本连不上。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 确认使用的是集群模式:
spring.redis.cluster.nodes已配置,且没同时配spring.redis.host - 启用主动拓扑刷新:
spring.redis.lettuce.cluster.refresh.period=30000(单位毫秒,建议 15–60 秒) - 开启自适应刷新:
spring.redis.lettuce.cluster.refresh.adaptive=true(遇到 MOVED/ASK 自动触发刷新) - 禁用错误降级:
spring.redis.lettuce.cluster.refresh.trigger.throttled=false(避免高频失败时限流)
reshard 迁移期间,客户端路由刷新必须同步触发
扩容后 MOVED/ASK 响应会激增,但若客户端没及时更新本地 slot 映射,就会持续把请求发到旧节点,造成缓存 miss 率飙升、DB 压力陡增。Jedis 或旧版 Lettuce 不调 clusterRefresh(),就只能等 timeout 后被动重试,中间全是超时窗口。
- 新节点上线后,立刻调用
RedisClusterClient.reloadPartitions()(Lettuce)或JedisCluster.refreshCluster()(Jedis) - 不要依赖“等它自己发现”,Lettuce 的
adaptive刷新虽能捕获 MOVED,但首次请求失败仍不可避免;建议在扩容脚本末尾加一次强制刷新 - 监控
redis-cli -c -h any_node info | grep cluster_stats中的cluster_known_nodes和cluster_size是否已更新,再放行业务流量
cluster-node-timeout 与 client timeout 不匹配会放大超时
集群内部故障检测周期和客户端超时不协调,会放大超时现象。比如 cluster-node-timeout 设为 15000ms,但客户端只等 2000ms,结果节点刚被标记 PFAIL,客户端已经报错退出。
-
cluster-node-timeout应设为网络 P95 延迟 ×2~3 倍(局域网常见 5000~8000ms,跨机房 12000~15000ms,容器环境不低于 8000ms) -
spring.redis.timeout建议 ≥cluster-node-timeout×1.5,至少留出握手、重定向、重试的时间余量 - 扩缩容前临时调大
cluster-node-timeout(如升至 20000),避免迁移抖动触发误判;操作完成后按需回调
真正难处理的,是那些拓扑刷新成功、地址也正确、但连接池里还躺着几十个指向已下线节点的空闲连接——它们不会主动断开,也不会被校验,直到某次业务请求把它捞出来,才第一次暴露超时。这时候光看日志看不出问题,得抓包或用 redis-cli client list 查连接来源和 idle 时间。

















