Redis 集群主从切换后客户端连接超时,通常是因为客户端缓存的集群拓扑结构未更新或超时配置过短。修复重点在于启用客户端拓扑刷新机制并调整网络超时参数。
先说结论:主从切换导致超时多因客户端仍连接旧主节点,需强制刷新拓扑或增加重试容错。
- 先确认:检查客户端使用的是 Lettuce 还是 Jedis,Lettuce 默认不自动刷新拓扑。
- 先处理:开启客户端拓扑刷新配置,同时增加 socket 超时时间。
- 再验证:通过日志观察重连行为,并使用 ping 命令测试连通性。
命令速用版
以下命令用于快速检查集群状态和网络延迟,辅助定位超时根源。
检查集群节点状态 redis-cli -h <ip> -p <port> cluster nodes 检查网络延迟 redis-cli -h <ip> -p <port> INFO latency 测试端口连通性 telnet <redis_ip> 6379 检查防火墙规则 (Linux) sudo ufw allow 6379
为什么会这样
客户端缓存了旧的集群拓扑信息,主从切换后请求仍发往已下线的节点。SpringBoot 2.X 版本开始 Redis 默认连接池采用 Lettuce,当节点发生改变后,Lettuce 默认不会刷新节点拓扑,导致客户端持续向旧主节点发送请求直至超时。此外,网络延迟过高或服务器负载过大也会导致连接请求在规定时间内无法完成。
分步处理
按照以下顺序排查配置和网络,确保客户端能感知拓扑变化。
1. 调整客户端拓扑刷新配置
如果使用 Lettuce,需在配置中启用自适应拓扑刷新。在 SpringBoot 配置文件中添加以下设置,确保节点变更时客户端能感知。
spring.redis.lettuce.cluster.refresh.adaptive=true spring.redis.lettuce.cluster.refresh.period=60s
2. 增加连接超时时间
客户端超时设置过短会在网络波动时直接报错。建议将 socket 超时时间调整至合理范围,例如 10 秒以上,避免瞬时抖动导致连接中断。
spring.redis.timeout=10000 spring.redis.jedis.pool.max-wait=10000
3. 检查网络与防火墙
确保客户端与 Redis 集群所有节点(包括新主节点)的网络连通。防火墙或安全组规则可能阻止了新节点的端口访问。使用 telnet 测试端口,确认 6379 端口开放。
怎么验证是否生效
通过日志和连接测试确认修复效果,观察是否仍有超时报错。
1. 观察应用日志
重启应用后,监控日志中是否不再出现"Connection timed out"或"Cluster topology refresh"相关错误。若使用 Lettuce,日志应显示拓扑刷新成功。
2. 模拟故障测试
在测试环境手动触发主从切换,观察客户端是否自动重连到新主节点且无报错。使用 redis-cli 执行 ping 命令,响应时间应在正常范围内。
3. 检查服务器状态
登录 Redis 服务器执行 INFO 命令,查看 connected_clients 和 rejected_connections 指标,确认连接数稳定且无异常拒绝。
常见坑
- Lettuce 默认行为:很多开发者忽略 Lettuce 默认不刷新拓扑的特性,导致切换后必须重启应用才能恢复。
- 硬编码节点 IP:客户端配置中若写死特定节点 IP,切换后无法发现新主节点,应使用集群种子节点列表。
- 防火墙遗漏:集群扩容或切换后,新节点的防火墙规则未同步开放,导致客户端无法连接新主节点。
- 超时设置过短:在高并发或网络波动场景下,默认的几秒超时可能不足,需根据实际网络状况调整。
常见问题
Lettuce 和 Jedis 在主从切换时有什么区别?
JedisSentinelPool 会自动从哨兵节点获取最新主节点信息,而 Lettuce 默认不会刷新节点拓扑,需要手动配置自适应刷新。
连接超时是服务器问题还是客户端问题?
两者都有可能,网络延迟、服务器负载过高或客户端超时时间设置过短都会导致连接超时,需结合日志和监控排查。
Redis 哨兵模式和集群模式超时处理一样吗?
不一样,哨兵模式依赖哨兵节点通知客户端主节点变更,集群模式依赖客户端维护槽位拓扑,配置重点不同。
参考来源
- Redis 集群连接超时解决之道 (redis 集群超时连接)
- Redis 集群 Lettuce 主从切换问题
- Redis 连接超时常见原因
- 解决 Redis 连接超时问题的全攻略
- Redis 中连接超时的报错与优化