一、问题现象
客户反馈访问服务端 HTTP 网页时,浏览器长时间处于加载转圈状态,页面无法正常打开或加载不完整。初步排查显示服务进程正常运行、端口可正常连接(TCP 三次握手成功),但页面内容无法完整传输。
二、抓包分析

在服务器侧使用 tcpdump 对相关连接进行抓包,重点观察不同大小数据包的收发情况,发现以下关键特征:
三次握手(SYN/SYN-ACK/ACK)等小包均正常收发,往返时延正常;
携带业务数据、长度为 1460/1500 字节(MSS 满载、DF 标志位置位)的 TCP 数据段,在多次连接中反复超时重传,且重传间隔按标准 TCP 指数退避规律增长(约 0.4s → 0.9s → 2s → 3.7s → 7s → 14s……),最终因重传耗尽被动以 FIN 关闭连接;
整个重传过程中,发送端始终未收到任何 ICMP 差错报文反馈;
上述现象呈现出典型规律:小包完全正常,大包(满 MSS、DF 置位)持续丢失且无差错反馈,指向经典的 Path MTU Discovery(PMTUD)黑洞问题。
三、诊断过程

在 Windows 客户端使用 ping 命令的 -f(禁止分片,等效 Linux 的 -M do)与 -l(指定负载大小)参数,对服务端地址进行分片探测,逐步调小包大小定位真实可通过的临界值。测试确认负载为 1448 字节时可正常通过,即:真实链路可承载的 MTU ≈ 1448 + 28(IP头20 + ICMP头8)= 1476 字节,明显小于标准以太网 MTU 1500 字节。
结合客户提供的网络拓扑信息:服务器为华为云 ECS,使用弹性公网 IP(EIP,NAT 转换)对外提供服务,客户端到服务端链路中经过 GRE 隧道封装。
GRE 隧道封装本身会额外占用约 24 字节(4 字节 GRE 头 + 20 字节外层 IP 头),与实测“MTU 较标准值少 24 字节(1500 → 1476)”完全吻合,由此可确认 MTU 缩小的来源即为链路中的 GRE 隧道封装。
进一步分析问题为何表现为“大包持续丢失、无法自愈”而非简单的性能下降:正常情况下,当报文超过某一跳的 MTU 且设置了 DF 标志时,该跳设备应丢弃报文并回送 ICMP Type 3 Code 4(Fragmentation Needed)消息,通知发送端调小后续报文;但本次链路中,该 ICMP 反馈报文在传输过程中被中间设备(GRE 隧道设备或安全组/防火墙)过滤或未正确送达发送端,导致标准 PMTUD 机制失效,发送端始终按原始大小重传,形成“黑洞”。
三、根本原因
链路中 GRE 隧道封装导致实际可用 MTU 由 1500 降至约 1476 字节,导致大包(满 MSS、DF 置位)经过隧道封装点时因超过 MTU 被丢弃。而对应的 ICMP“需要分片”差错报文未能送达发送端(被隧道设备或安全组/防火墙过滤),导致标准 PMTUD 机制失效,形成 PMTU 黑洞。客户端的现象就是TCP 握手等小包正常,携带页面内容等大包反复重传直至连接超时,浏览器长时间转圈、页面无法完整加载
四、问题处理
- 启用 TCP MTU Probing,修改内核参数:sysctl -w net.ipv4.tcp_mtu_probing=1,使 TCP 协议栈在检测到大包反复重传时,主动探测并降低 MSS,不再依赖 ICMP 反馈:
- 若应用采用容器化部署,可通过修改 Docker daemon.json 从源头限制容器发出报文的大小:{ "mtu": 1476 },该配置需重启 Docker 服务生效。
五、验证结果
在服务器开启 net.ipv4.tcp_mtu_probing=1 后,限制容器报文大小后,客户端浏览器可正常打开网页,页面完整加载,未再出现长时间转圈现象,问题已解决。
六、总结
本次故障的本质是 GRE 隧道封装降低了链路实际 MTU,叠加中间设备对 ICMP 差错报文的过滤,导致经典 PMTUD 机制失效,属于典型的“大包黑洞”问题,具有较强隐蔽性(服务、端口、握手均正常,容易被误判为应用层问题)