ping 有回显,远程桌面也能用,浏览器却停在空白页直到放弃。这种情形有两种解释,而它们并不是同一个问题的变体:策略从未放行该服务,或者传输变大后包不再放得下。回显应答对这两种可能都不作排除。

从最小的问题问到最大的问题,并记录每一步究竟证明了什么。

回显应答回答的是一个更小得多的问题

回显应答说明目标主机的 IP 栈回应了来自你这一端的 ICMP 请求。它不能说明你需要的端口上是否存在 TCP 监听,不能说明策略是否放行该端口,也不能说明目标主机是否绕开网关自行过滤流量。允许一项服务的网关完全可能丢掉另一项,而两个目标对 ping 都有应答。请把这条应答当作关于一个包、一个方向的一条事实。

在解释任何其他东西之前,先确认目标和服务端口。你测试的地址和应用实际使用的地址有时是两条不同的记录,而一个解析到两个地址的名字会让这种情况更可能出现。

先弄清连接有没有建立

立刻被拒绝的连接是监听或策略给出的回答:有东西回应了,而且说了不行。能建立、但一开始传数据就卡住的连接指向大小问题。完全无法完成握手的连接通常是策略或路由问题,表现更像超时而不是拒绝。

curl -v --max-time 10 https://internal.example/ -o /dev/null
ss -tn state established '( dport = :443 )'

在动 MTU 设置之前,先记下你看到的是这三种里的哪一种。为了修好一个被拒绝的连接而去改隧道大小,既浪费了这次改动,也会在一段时间里掩盖真正的原因。

用一个说明白了的数字来测量大小

负载下出现卡顿时,在设置禁止分片位的前提下测一个包大小,并把算式写清楚,结果才有意义。在装有 iputils 的 Linux 上,1392 字节的净荷加上 8 字节 ICMP 头和 20 字节 IPv4 头,得到的内部包正好是 1420 字节。把这份算式写进工单,因为一个只到网关的裸 ping 对应用什么都证明不了。

ping -4 -M do -s 1392 10.44.0.10
ping -4 -M do -s 1372 10.44.0.10

两种探测都是测量点,而不是隧道大小的建议值。如果路径上任何位置过滤了 ICMP,超时就不能说明大小,因为从客户端看,过滤和包过大是一回事。一次成功同样不能说明反方向,也不能说明另一个目标。

把外层路径算进去

封装会带上自己的头部,所以线路上的包比你在隧道里测到的包更大。正是这两者之间的差额,让一个能通过的小请求和一个失败的大请求可以同时存在。

IPv4 的路径 MTU 发现依赖关于无法在不分片的情况下转发的包的反馈,IPv6 则使用 Packet Too Big 消息。IPv4 规范描述了这一机制。过滤掉反馈会破坏发送方学习的能力,使它反复重传永远不会放得下的包。这就是为什么能通过的小请求和失败的大请求可以如此安然共存。

改一个数字,再测一次应用

调低隧道 MTU,或者限制 TCP 的最大报文段大小,然后重做原来的应用测试,而不是重做探测。改动之后探测成功、应用仍然卡住,那是形状相似的另一类问题,只有应用测试能区分它们。

把算式留在变更记录里:测得的包大小、你假设的额外开销,以及你实际设置的值。日后复查的人可以核对这个假设,而不必从一张 ping 截图重新推一遍。

如果你试过的每一种大小下应用都能用,那就别再调数字,去看看把能用的服务和失败的服务分开的那条策略。

相关文章