mtu不一致导致redis集群slave频繁掉线,因心跳包(>1.5kb)在mtu较小路径上被分片,中间设备丢弃分片致pong丢失、超时标记pfail;需tcpdump抓包验证,调大cluster-node-timeout、启用tcp-keepalive及内核限速规避。

Redis集群因MTU设置不当导致的丢包和延迟,不是Redis本身慢,而是TCP层在 silently 丢包——你看到ping正常、mtr无丢包,但CLUSTER NODES里节点反复变fail,cluster_stats_messages_pong_sent延迟飙升,基本就是这个原因。
怎么确认是MTU问题不是Redis配置错
别信ping -c 4 <slave-ip></slave-ip>,它走ICMP、包小(默认56字节),根本触发不了分片;也别只看redis-cli -c -h <master-ip> info cluster</master-ip>里的统计字段,那是结果,不是根因。必须抓真实Gossip流量:
- 在主从节点**同时**执行:
tcpdump -i any 'port 6379 and (tcp[12:1] & 0xf0) > 0x50' -w heartbeat.pcap(过滤掉纯ACK,只留含数据的TCP包) - Wireshark里加载后,用过滤器:
tcp.len > 0 and tcp.flags.syn == 0,重点找:IPv4 fragment、TCP segment not captured in full、或大量[TCP Retransmission] - 运行
ss -i dst <slave-ip>:6379</slave-ip>,观察retrans列是否持续非零、loss是否增长、wscale是否频繁抖动
为什么调大cluster-node-timeout只是缓兵之计
把cluster-node-timeout从默认15000改成30000,确实能让节点“多活几秒”,但掩盖了丢包本质——PONG包压根没到,超时只是必然结果。更危险的是,这会拖长故障发现时间,且无法解决同步延迟或master_last_io_seconds_ago持续>1的问题。
-
cluster-node-timeout设太高:脑裂风险上升,分区恢复时可能选错主节点 -
cluster-node-timeout设太低:网络抖动就误判PFAIL,触发无谓的故障转移 - 真正要压的是分片概率,不是延长容忍窗口——所以优先做
tcp-keepalive 60+ 内核限速,再考虑调timeout
不改系统MTU的前提下如何让Redis“适配”小MTU链路
云环境通常禁止改ifconfig eth0 mtu 1400,强行改还可能导致SSH断连或元数据服务异常。更安全的做法是让Redis通信行为收敛:
- 所有节点
redis.conf中加:tcp-keepalive 60(激活保活,防NAT清连接) - 用
tc在宿主机限速,压制突发大包:tc qdisc add dev eth0 root tbf rate 10mbit burst 16kbit latency 100ms - 避免依赖单次大PING:Redis 8.2.3+已优化Gossip打包逻辑,但若仍在用旧版,务必升级——CVE-2025-62507修复本身也包含心跳流稳定性改进
终极验证:别只看状态,要看PONG是否真抵达
改完配置后,不能只跑redis-cli -c -h <slave-ip> CLUSTER NODES</slave-ip>看状态是不是connected。要进节点执行:
redis-cli -h <master-ip> info cluster | grep -E "cluster_stats_messages_pong_(received|sent)"</master-ip>
观察cluster_stats_messages_pong_received与sent的差值是否稳定在个位数(理想是0),且cluster_stats_messages_pong_sent的平均延迟回落至rtt的1.5倍以内(用ss -i查到的rtt值)。如果差值仍>100或延迟>200ms,说明分片或丢包仍在发生,得回头检查tc规则是否生效、tcp-keepalive是否被防火墙拦截。











