问题背景
我们两个机房(A 机房应用集群、B 机房数据库与文件存储)之间通过一条站点到站点的 IPSec VPN 隧道互联,跑了大半年一直平稳。某次业务扩容后,运维群里陆续冒出几条零散反馈:A 机房的备份任务往 B 机房的存储推文件时经常"卡住不动",跨机房的 MySQL 主从同步偶尔中断重连,个别同事反映从 B 机房拉大的日志包会在中途"僵住"。
但奇怪的是,这些抱怨都不"稳定"——同一个人换个小文件、换个时间点又一切正常。网络监控上带宽、丢包、延迟三条曲线都健康得很,隧道状态 up,ping 对端也是稳稳的 0 丢包。于是问题被当成"偶发抖动"拖了两天,直到一次跨机房的数据库全量同步在传到几百 MB 时彻底断掉、重试三次都失败,才被正式立项排查。
故障现象
把现象归拢后,特征异常清晰又诡异:
- 小流量全通,大流量必卡。
ping(默认 64 字节)0 丢包;SSH 登录、执行短命令、curl拉小页面都秒回。但只要是持续的大数据传输——scp大文件、rsync全量、mysqldump跨机房导入——传输曲线都会走到某个点后骤降为 0,连接不报错、就是永久挂起,直到超时。 - 方向不对称。从 A→B 推大文件几乎必卡;B→A 拉反而好一些,但也偶发。
- 协议无关。HTTP、MySQL、NFS 全中招,说明不是应用层的问题。
- 同机房内部完全正常。同样的传输在各自机房内部跑,速度拉满、毫无问题。问题只出现在"跨隧道 + 大数据量"这个交集上。
“ping 通但大文件传不动"这组症状,几乎是 MTU/分片类问题的教科书式指纹。方向立刻收敛到链路 MTU 上。
排查过程
第一步:用带 DF 标志的大包探测路径 MTU。 普通 ping 用小包,掩盖了问题。我改用大包 + 禁止分片(DF)来探路。Linux 下:
|
|
结果非常关键:
-s 1472(整包 1500):100% 丢失,且没有收到任何 “Frag needed” 的 ICMP 回包,就是静默超时。-s 1400(整包 1428):依旧不通。-s 1300附近开始逐步能通,二分下去,实测隧道能稳定通过的整包上限在 1422 字节左右。
这解释了一切:隧道的实际可用 MTU 远小于以太网标准的 1500。IPSec 封装(ESP 头 + 认证 + 可能的 NAT-T UDP 封装)会给每个包额外增加几十字节开销,把有效载荷 MTU 压到了 1400 出头。
第二步:确认这是"PMTUD 黑洞"而非普通 MTU 不匹配。 正常情况下,当一个 1500 的 DF 包进不了小 MTU 的链路时,中间设备应该回一个 ICMP Type 3 Code 4(Fragmentation Needed and DF set)告诉发送方"请把包改小到 1422”,这就是路径 MTU 发现(PMTUD)。发送方收到后会自动缩小该目的地的 MSS,传输就能恢复。
但我们的探测里,大包是静默丢弃、没有任何 ICMP 反馈。抓包印证了这一点:
|
|
发送方永远等不到"包太大"的通知,就会一直用 1500 的大包硬发、永远被丢,同时因为 TCP 已经建连(三次握手是小包,能通),应用层只看到"传着传着就不动了"。这正是 PMTUD 黑洞(PMTUD Black Hole):ICMP 差错报文在路径某处被吞掉,导致路径 MTU 发现机制失效。
第三步:定位 ICMP 被谁吃掉。 沿着隧道两端逐跳排查防火墙策略,发现 B 机房出口防火墙上有一条几个月前为"防 ICMP 洪水"加的粗暴规则——直接 deny 了所有入向 ICMP。这条规则把正常的 echo 挡了(但因为大家平时 ping 的是内网网关、没走到这条规则,一直没暴露),更致命的是把 PMTUD 赖以工作的 Type 3 Code 4 差错报文也一并丢弃了。
第四步:解释方向不对称。 A→B 更容易卡,是因为 A 机房应用发出的大包在进入隧道后触达小 MTU,而回程的 ICMP 差错又被 B 侧防火墙拦截;B→A 方向的差错报文路径不同、部分能漏回来,于是表现"好一点"。至此,因果链完全闭合。
解决方案
处理分两层:先恢复 PMTUD,再用 MSS 钳制兜底,双保险。
1. 放行 PMTUD 必需的 ICMP。 在 B 机房出口防火墙上,把"一刀切 deny ICMP"改为精确放行差错类报文(尤其是 Type 3 Code 4),仅对 echo-request 做限速而非全禁:
|
|
2. 在隧道网关上做 TCP MSS 钳制(MSS clamping)。 这是应对 MTU 受限隧道最稳妥的通用手段——不依赖 ICMP 是否可达,直接在网关改写经过的 TCP SYN 包里的 MSS 选项,强制两端协商出一个不会超限的分段大小。按隧道实测 MTU 1422 计算,MSS = 1422 − 40(IP+TCP 头)= 1382,保守取整用 1360:
|
|
网络设备(如思科/华为)上对应的是 ip tcp adjust-mss 1360 配到隧道接口。
改完立刻复测:scp 大文件、rsync 全量、跨机房 MySQL 同步全部一次性跑通、速度稳定。之前必卡的几百 MB 全量导入顺畅完成。
根因分析
根因是两个独立因素在"大包 + 跨隧道"场景下叠加:
- IPSec 封装开销压低了隧道有效 MTU,1500 的标准以太网包进隧道后超限;
- B 侧防火墙一刀切禁用 ICMP,掐断了 PMTUD 的反馈通道,让本可自愈的 MTU 问题恶化成静默黑洞。
单独任一因素都不致命:只有封装开销,PMTUD 能自动降 MSS;只有禁 ICMP,若无小 MTU 链路也无害。两者相遇,才造出"ping 通、小包通、大包静默死"这种最难缠的间歇性故障。而 TCP 建连用小包能成功、真正的数据传输才触发大包,正是它伪装成"应用偶发卡顿"的原因。
预防措施
- 隧道/Overlay 网关默认配置 MSS 钳制:凡是 IPSec、GRE、VXLAN、PPPoE 等有封装开销的链路,一律在网关上启用
clamp-mss-to-pmtu或按实测 MTU 固定 MSS,不要指望 PMTUD 一定可用。 - ICMP 不要一刀切禁用:Type 3(尤其 Code 4 fragmentation-needed)、Type 11(time-exceeded)必须放行,防洪应对 echo 用限速而非全禁。把这条写进防火墙基线评审清单。
- 上线跨链路业务前做大包连通性验证:用
ping -M do -s <size>二分探测真实路径 MTU,纳入变更验收,而不是只ping一下就签字。 - 监控补一条大包探针:在跨机房链路上定时发 DF 大包做拨测,MTU 收缩能第一时间告警,而不是等业务传大文件才发现。
- 变更留痕:那条"防 ICMP 洪水"的规则加的时候没评估副作用。任何安全策略变更都应评估对 PMTUD/路径探测的影响。
总结
这次故障的迷惑性全在于"ping 通"给人的虚假安全感——小包能过不代表链路健康,大包才是真正的试金石。排查的关键转折是改用带 DF 的大包探测,一眼看穿隧道 MTU 被压缩,再顺着"为何没有 ICMP 反馈"揪出被防火墙吞掉的 PMTUD 通道。对所有带封装的隧道链路,记住两条铁律:默认做 MSS 钳制,永远不要一刀切禁 ICMP 差错报文。把这两点固化进基线,这类"小包通、大包死"的幽灵故障就能从源头杜绝。