小请求通得过,大响应卡住
一句话总结
如果用 curl 能收到 header,却在正文处停住,十有八九是 MTU 黑洞。
能够建立连接,与大数据包能够通过,是两个不同的问题。
为什么需要了解这一点
这种症状会困扰人很久。
curl -I(仅 header)→ 立即成功curl(完整内容)→ 停顿数秒后 timeout- 小型 API 响应正常,只有列表查询失败
- 开启 VPN 时能够复现,关闭后则不会
因为“能够连接”,所以不会怀疑防火墙;又因为“偶尔能用”,所以判断也不是 DNS。 真正原因是路径中的某个位置悄悄丢弃了大数据包。
MTU 与 PMTUD
MTU(Maximum Transmission Unit)是一次能够发送的数据包最大尺寸。 以太网通常为 1500 字节。
问题出在路径中间存在 MTU 更小的区段时。
클라이언트(1500) → 라우터 → VPN 터널(1400) → 서버(1500)
TCP 建立连接时,双方会互相告知“我最多可以接收 1460 字节(MSS)”。 但这只是两端的情况,不代表中间区段的情况。
正常情况下,它会这样工作:1500 字节的数据包到达 1400 的区段时, 对应 router 会发送 ICMP "Fragmentation Needed",告知“数据包太大,请缩小到 1400”。 发送方缩小尺寸后重新发送。这个过程称为 Path MTU Discovery。
阻止 ICMP 会形成黑洞
许多组织认为“ICMP 很危险”,于是在防火墙中将其全部阻止。随后就会发生以下过程。
- 大数据包到达 MTU 较小的区段
- router 将其丢弃并发送 ICMP
- ICMP 被防火墙阻止
- 发送方得不到任何消息,继续以相同尺寸重传
- 永远失败,也没有错误消息
这就是 PMTUD 黑洞。小数据包(handshake、header request)可以通过, 只有大数据包(正文)会消失,所以症状才如此令人困惑。
诊断——无需特权的检查方法
通过 ping -M do -s 改变尺寸进行测量是教科书式方法,但
ping 需要 NET_RAW capability,在受限环境中无法使用。
好在还有其他方法。
1. 检查路径和 MTU
ip route get 8.8.8.8
# 8.8.8.8 via 10.0.0.1 dev eth0 src 10.0.0.5
ip -o link show # 각 인터페이스의 mtu 값
cat /sys/class/net/eth0/mtu
2. 改变响应尺寸进行复现
curl -s -o /dev/null -w '%{size_download} %{time_total}\n' \
'https://api.example.com/items?limit=1'
curl -s -o /dev/null -w '%{size_download} %{time_total}\n' \
'https://api.example.com/items?limit=1000'
只有小响应成功,是一个强烈信号。
3. 分开检查 header 与正文
curl -I https://target/ # 헤더만 → 성공?
curl --max-time 5 https://target/ # 전체 → 멈춤?
4. 查看 socket 状态
ss -tin dst 10.0.3.20
# ... mss:1460 ... retrans:0/14 ...
retrans 持续增加,表示正在反复发送同一个数据包,
这是 MTU 黑洞的典型指纹。
应对方法
| 应对方式 | 方法 | 备注 |
|---|---|---|
| 允许 ICMP | 至少在防火墙中开放 type 3 code 4 | 根本解决方案 |
| 降低 interface MTU | ip link set eth0 mtu 1400 |
需要特权 |
| MSS clamp | 在 router/firewall 中让 MSS 与路径匹配 | 常见现场方案 |
| 缩小应用响应 | pagination | 只是绕过问题 |
现场最常使用的是 MSS clamp。如果 gateway 把 TCP handshake 的 MSS 值降低到符合路径 MTU,最初就不会生成大数据包。
同时检查路由
也有可能不是 MTU。如果 ip route get 指向的 interface 与预期不同,
问题就在路径本身。
ip route get 10.0.5.10
# dev eth1 이 나온다면 — eth0 로 갈 줄 알았는데 아니었다
ip rule show # 정책 라우팅이 있는가
ip route show table all
开启 VPN 后,default route 整体发生变化的情况很常见。此时本应发往内部网络的 流量可能会进入 VPN,反之亦然。
实际工作中的表现
- 只有 VPN 用户的文件下载停顿 → tunnel MTU + ICMP 阻断。
- 迁移到 cloud 后,只有特定 API timeout → overlay network 的 MTU 下降。
- 仅在 container 中复现 → CNI 的 MTU 设置与 host 不同。
后续测验将检查什么
检查为何只有小请求成功的现象指向 MTU 黑洞,以及能否把 ss -tin 中
不断增加的重传与其他正常指标区分开。