MTU不一致会导致Redis从节点频繁掉线,因心跳包(>1.5KB)在MTU较小路径上被分片,而中间设备常丢弃分片包,致PONG丢失、超时标记PFAIL;需通过tcpdump抓包验证,并调大cluster-node-timeout、启用tcp-keepalive及内核限速规避。
Slave节点频繁掉线,大概率不是Redis配置错了,而是网络层在 silently 丢包——尤其当MTU设置不匹配、心跳包被分片或直接截断时。
Redis集群节点间的心跳(PING/PONG)默认走TCP,但实际封装在Gossip消息里,单个PING包可能达1.5KB以上。若主从节点所在网络路径中某段设备(如VPC网关、安全组、物理交换机)MTU设为1400,而节点系统MTU仍为1500,就会触发IP分片。而很多云厂商或中间设备默认禁用IP分片或丢弃分片包,结果就是PING发出去了,PONG收不回来,cluster-node-timeout一到就标记PFAIL。
这种丢包不会出现在ping测试里(ICMP包小),也不会被mtr的ICMP探测捕获,必须看真实TCP流。
ss -i dst <slave-ip>:6379</slave-ip>检查重传(retrans)、SACK丢失(loss)、窗口阻塞(wscale)字段是否异常波动tcpdump -i any 'port 6379 and (tcp[12:1] & 0xf0) > 0x50' -w cluster-heartbeat.pcap(只抓TCP头≥80字节的包,过滤掉纯ACK)tcp.len > 0 and tcp.flags.syn == 0,看是否有大量IPv4 fragment或TCP segment not captured in full
不要直接改系统MTU——Redis集群通信是双向的,主从角色可互换,且部分云平台禁止修改网卡MTU。更稳妥的做法是让Redis“主动适配”:
redis.conf中显式设置:tcp-keepalive 60(激活TCP保活,避免NAT清连接表)cluster-node-timeout至至少20000(20秒),给分片重传留出缓冲时间tc qdisc add dev eth0 root tbf rate 10mbit burst 16kbit latency 100ms(压低突发,减少大包集中发送)redis-cli -c -h <slave-ip> CLUSTER NODES</slave-ip>,观察返回的节点列表中目标Slave状态是否稳定为connected而非disconnected或fail?
一是cluster-node-timeout不能只看数值,它必须大于路径中最大RTT的3倍——如果mtr --tcp -P 6379 <slave-ip></slave-ip>显示某跳RTT抖动σ>150ms,那cluster-node-timeout设成30000都不够;二是所有节点的tcp-keepalive必须统一,否则保活周期错位,会出现“主认为连着,但从认为断了”的单向失联。
真正难处理的,从来不是参数调多少,而是你得先确认那个丢包的跳点,到底是在云厂商的BGP边界,还是自己机房的ToR交换机buffer溢出。