cluster-node-timeout应设为节点间gossip p95延迟的2~3倍,局域网5000~8000ms、跨机房12000~15000ms、k8s环境不低于8000ms;须全节点一致配置并重启生效,同时启用tcp-keepalive≥60且≤timeout/3。

直接调高 cluster-node-timeout 并不解决问题,真正要防的是“误判触发连锁反应”。核心是让主观下线(PFAIL)不轻易发生,且即使发生也不扩散成客观下线(FAIL)和自动故障转移。
怎么判断当前 cluster-node-timeout 是否压得太低
别只看配置值或文档建议,得看节点间真实心跳延迟分布:
- 在任意主节点上执行
redis-cli -c -h nodeA -p 6379 cluster nodes,挑出非myself的几行,找每行末尾类似ping-sent=1718923456789 pong-recv=1718923457021的字段,差值就是单次 Gossip 往返耗时(单位毫秒) - 对所有节点持续采集 5 分钟,汇总所有差值,取 P95 值(不是平均值,也不是最大值)
- 若 P95 是 2200ms,那么
cluster-node-timeout至少设为6600(3×P95),局域网可设8000,K8s 环境建议10000 - 如果改完后
cluster nodes输出里仍有大量fail?状态跳变,说明要么值仍不够,要么网络丢包/重传已实际发生
为什么 CONFIG SET cluster-node-timeout 经常不生效
这个命令只改当前节点内存状态,重启即丢,而且集群中只要有一个节点的值和其他节点不一致,Gossip 投票逻辑就失效:
-
CONFIG SET后必须立刻用CONFIG GET cluster-node-timeout确认返回值已更新 - 但更关键的是:所有节点的值必须完全一致,差 1 毫秒都可能导致部分节点认为“已 FAIL”,另一些还认为“只是 PFAIL”
- 持久化必须改每个节点的
redis.conf,然后发SIGUSR1或逐个重启;不能只改一部分节点再等集群同步 - 验证是否真正生效:等 2 分钟后运行
redis-cli --cluster check 127.0.0.1:7001,必须返回[OK] All 16384 slots covered.
光调超时还不够:必须配好 TCP 层保活
cluster-node-timeout 是应用层判定依据,但如果底层 TCP 连接已被中间设备(如云安全组、iptables conntrack、CNI 插件)静默断开,PING 就根本发不出去,直接触发超时误判:
- 确认所有节点的
tcp-keepalive都已启用,推荐设为60(每 60 秒发一次 keepalive 包) -
tcp-keepalive值必须 ≤cluster-node-timeout / 3,否则 keepalive 还没发出去连接就断了 - 禁用防火墙或安全组对端口
6379(客户端)和16379(集群总线)的连接数限制或老化策略 - 在容器/K8s 环境,务必检查 CNI 插件是否开启 conntrack,某些插件默认老化时间仅 30 秒,远低于 Redis 心跳节奏
最易被忽略的一点:集群扩缩容前必须临时调大 cluster-node-timeout。加节点时握手密集、迁移槽位时 CPU 和网络压力陡增,此时若沿用原值,新老节点极易互相标记 PFAIL,引发短暂但剧烈的状态震荡——这不是配置错误,而是设计使然。











