一台云主机 SSH 连得上,敲命令有回显;ping 网关通、ping 公网通;curl 首页能拿到 HTML,浏览器标签页上的标题也刷出来了。然后你 scp 一个 200MB 的日志包过去,进度条停在 0%,一动不动。换个 20KB 的配置文件再传,秒传成功。工单里对这类现象最常见的描述是"网络时好时坏",但它跟带宽、跟丢包率、跟线路质量一点关系都没有。(以下为典型故障场景描述,并非特指某一真实客户案例。)
ping -M do -s 二分出真实路径 MTU,再决定是改隧道口 MTU 还是做 MSS 钳位。一上来把 MTU 改成 9000 是最典型的反向操作。把上面那个现象拆开看,会发现它有一个非常整齐的规律:凡是"小"的都通,凡是"大"的都不通。SSH 登录时的密钥交换报文不超过几百字节,登录成功;登录后敲一条 ls,返回的目录列表只有几百字节,正常显示;scp 传 20KB 文件,TCP 把它切成十几个包,每个包都在 MSS 以内,秒传;200MB 的文件要切成十几万个满载包,卡在第一批就再也不动了。
这类故障最迷惑人的地方在于,它几乎能骗过所有常规的网络健康检查。ping 默认只发 56 字节(部分发行版 64 字节)的载荷,加上 8 字节 ICMP 头和 20 字节 IP 头,整包不到 100 字节,当然通。mtr 默认也发小包,跳数和延迟都很漂亮。运维看到这一串绿油油的结果,第一反应是"网络没问题,是不是应用层的问题",然后开始在应用日志里翻,越翻越远。
我在工单里还有一个高频变体:网站能打开标题,页面内容永远加载一半。原因是 HTML 文档本身可能就 5KB,一次响应就回来了;而首屏那几张图、那个 300KB 的 JS bundle、那个被内联进来的字体文件,全都超过了路径能承载的单个报文大小。浏览器渲染出标题就停住,控制台里挂着几个 pending 的请求,等 30 秒超时后变成 failed。用户看到的现象是"网站坏了",实际的物理事实是"大于 1400 字节的包全被丢了"。
还有一个更隐蔽的版本:HTTPS 握手成功,但 body 传不完。TLS 握手阶段的 ClientHello、ServerHello、密钥交换报文普遍在几百字节量级,能过;一旦进入应用数据传输,HTTP 层开始下发大块数据,连接就挂了。反过来,如果服务端证书链特别长(多级中间 CA + OCSP 装订),握手阶段的 Certificate 报文本身就可能超过 1400 字节,这时连握手都完成不了,表现为"这个网站直接打不开"——而同机房、证书链短的站点却一切正常。
MTU(Maximum Transmission Unit)是二层一次能承载的最大 IP 报文,标准以太网是 1500 字节。MSS(Maximum Segment Size)是 TCP 层一次愿意接收的最大 payload,它在三次握手的 SYN 包里通过 TCP 选项通告给对端,双方各说各的,取较小值执行。
换算关系很干净:MSS = MTU − IP 头(20)− TCP 头(20)。所以 1500 的 MTU 对应 1460 的 MSS;如果开了 TCP 时间戳选项,TCP 头变成 32 字节,MSS 相应降到 1448。ss -i 里经常能看到 1448 这个数,不是配错了,是时间戳占掉了 12 字节。
关键在于:MSS 是主机在握手时根据自己的网卡 MTU 算出来的,它并不知道中间链路上有什么。一台网卡 MTU 1500 的机器,发出的 SYN 里就写着 MSS 1460。它对端会照着这个数发满载包,每个包 1500 字节。
Linux 默认对 TCP 报文置 DF(Don't Fragment)位,也就是 net.ipv4.ip_no_pmtu_disc = 0,PMTUD 是开着的。置了 DF 的报文遇到一个 MTU 更小的出接口时,路由器不能分片,只能丢弃,然后应当回一个 ICMP Type 3 Code 4 —— Destination Unreachable / Fragmentation Needed and DF Set —— 报文里还带着下一跳的 MTU 值。发送端收到它,就知道这个目的地只能走 1400,于是把该目的地的 PMTU 记进路由缓存,后续报文按 1400 发,MSS 相应降到 1360。
这套机制跑得很顺的时候,你甚至感觉不到它的存在。问题出在"应当"两个字上。现实里大量网络出于安全考虑直接把 ICMP 一刀切掉:iptables -A INPUT -p icmp -j DROP、云上安全组默认只放行"全部 ICMP"或"全不放行"两个极端、运营商侧对 ICMP 限速、某些负载均衡设备不回 unreachable。于是那台 MTU 更小的路由器老老实实发了 ICMP need frag,报文却在回程路上被丢得干干净净。
发送端这边的状态是:发了满载包,没收到 ACK,重传,还是没 ACK,退避,再重传,一直重传到应用层超时。它从头到尾不知道自己该把包变小,因为它从来没收到过那个告诉它"你该变小"的报文。这就是 PMTUD 黑洞(PMTU black hole),也是"小的行大的不行"的全部物理原因。整条链路上没有任何设备在报错,没有任何一条日志说"包太大了",你只能从症状去反推。
这里有个非常实用的判读分水岭:当你用 ping -M do -s 1472 去打,如果 PMTUD 是通的,你会看到明确的回显,比如 Linux 上 From 10.0.0.1: icmp_seq=1 Frag needed and DF set (mtu = 1400),Windows 上是 Packet needs to be fragmented but DF set。如果 PMTUD 被掐断了,你什么都看不到——就是纯超时,一行提示都没有。有没有那行 "Frag needed",直接告诉你这是"路径确实变窄了"还是"窄了但没人通知你",两种情况的处置力度完全不同。
纯物理链路上的 PMTUD 黑洞其实不多见,因为运营商设备的 MTU 通常是一致的。真正高发的是链路上多了一层封装的场景:GRE、IPsec、VXLAN、WireGuard、OpenVPN、容器网络,全算。
道理很直白。假设物理口 MTU 是 1500,你在上面起一条 GRE 隧道。原始 TCP 报文 1500 字节进来,系统要给它套一个新的 IP 头(20)+ GRE 头(4),于是外层报文变成 1524 字节,超过物理口 MTU,直接发不出去。如果你的隧道口 MTU 也是 1500,这条隧道里的每一个满载包都是废包。
不同封装的开销是个需要背下来的表,排查时一查一个准:
把这些数摆在一起,结论就很清楚了:每加一层封装,可用的 payload 就少一截,但隧道口的 MTU 如果你不去显式设置,很多实现会默认照抄物理口的 1500。这时候端到端发出来的每个满载包,都是"我看得见、链路上发不出去、丢了还无人通知"的死包。隧道本身是通的(隧道保活、隧道内的小包、隧道建立过程都没问题),所以监控看不出异常,业务却全线卡死。
还有一种更麻烦的情况:隧道两端 MTU 配得不一样。A 端隧道口 1400、B 端 1500,那么 B→A 方向会出问题,A→B 方向正常。这解释了为什么"我这台机器访问对端没事,对端访问我就卡"。路径 MTU 是有方向的,两个方向必须各测一次,这点在后面的定位步骤里会反复强调。
把上面讲的机理落到工单语言上,下面这张对照表可以直接当排查手册的第一页用。左边是你听到的现象,右边是"敲哪条命令、看到什么就算确认"。
| 表现 | 最可能的原因 | 一条命令先验证 | 看到什么就能确认 |
|---|---|---|---|
| ping 通、scp 小文件秒传、大文件永远 0% | 路径 MTU 小于接口 MTU,且 PMTUD 黑洞 | ping -M do -s 1472 目标IP |
纯超时、没有任何 "Frag needed (mtu=xxxx)" 提示 = ICMP 被丢;有提示则 PMTUD 正常、只是路径真的窄 |
| 网页标题刷出来了,图片和 JS 加载一半 | HTML 小响应能过,大资源报文超限被丢 | curl -s -o /dev/null -w '%{size_download}\n' 大文件URL |
下载字节数停在一个固定值不再增长,然后连接超时,而不是报 404/500 这类应用层错误 |
| HTTPS 握手成功但 body 传不完;部分站点直接打不开 | 证书链长的站点握手报文本身就超限;TLS 记录大于路径 MTU | tcpdump -ni any 'tcp port 443' -vv |
同一个 seq 号反复出现 TCP Retransmission、对端无 ACK,且没有任何 ICMP 回包 |
| 数据库单条插入正常、批量插入卡死 | 单条报文小,批量 INSERT 的报文远超 MSS | 另开窗口 ss -ti '( dport = :3306 )' |
mss 仍显示 1460 / pmtu 仍显示 1500,而实际路径只支持 1400;retrans 计数持续上涨 |
| 只有部分 CDN、部分站点有问题,另一些完全正常 | 去往不同目的地的路径不一致,MTU 瓶颈在不同跳 | 对正常与异常目标各做一次 tracepath |
两者结尾的 Resume: pmtu xxxx 数值不同;异常目标那一侧明显更小 |
| 隧道建起来之后,原本正常的业务开始卡 | 封装头吃掉了 payload 空间,隧道口 MTU 未同步下调 | ip link show 看隧道口,tracepath 目标 看路径 |
隧道口 MTU 仍是 1500,而 tracepath 报出 pmtu 1400/1450/1436 之类比 1500 小的数 |
定位这一步的顺序不能乱。很多人上来就改 MTU,改完发现有的业务好了有的更糟,然后又改回去,来回折腾几轮才想起来"我其实不知道真实路径 MTU 是多少"。先把数字测出来,所有后续决策才有依据。
-M do 表示禁止分片(DF 置位),-s 指定的是 ICMP 载荷字节数,不含 ICMP 头 8 字节和 IP 头 20 字节。所以:
ping -M do -s 1472 目标 → 1472 + 8 + 20 = 1500,等价于测"1500 能不能过"。-s 值,加 28 就是这条路径的 MTU。-c 2 -W 2 可以显著加快探测速度,不用等默认的一秒一发。判读刚才说过了,再强调一次:"Frag needed and DF set (mtu = 1400)" 这行回显本身就是最值钱的信息——它既告诉了你 ICMP 是通的(PMTUD 没被掐),又直接给了你答案。看到它,你就可以跳过二分法,直接把 1400 记下来。反之如果只超时不回显,说明这条路是黑洞,你必须自己二分,并且后面大概率要靠 MSS 钳位或降接口 MTU 来治,光靠放行 ICMP 未必来得及。
macOS 上对应的写法是 ping -D -s 1472 目标(-D 置 DF)。
Windows 的 ping 用 -f 置 DF,-l 指定载荷大小,换算方式和 Linux 一样:ping -f -l 1472 目标 测的是 1500。返回 Packet needs to be fragmented but DF set 说明 ICMP 通、路径窄;返回 Request timed out 且小值能通,说明是黑洞。
tracepath 目标 是这套排查里性价比最高的命令,它一边 trace 一边直接把路径 MTU 探测结果打出来,典型输出长这样:
1?: [LOCALHOST] pmtu 1500
1: 10.0.0.1 0.417ms
2: 10.0.0.1 0.512ms pmtu 1400
3: 203.0.113.1 3.214ms
4: 198.51.100.7 5.118ms reached
Resume: pmtu 1400 hops 4 back 4
第 2 跳那个 pmtu 1400 就是答案,结尾的 Resume: pmtu 1400 是最终结论。注意这一跳同时也是瓶颈所在的网络位置,如果你认得那个 IP 属于哪台设备(防火墙?隧道网关?某条运营商链路?),处置方案基本就出来了。Windows 上没有 tracepath,可以用 ping -f -l 手二分,或者装 tracetcp。
路径 MTU 测出来之后,回到本机核对几个数,看看它们之间是不是对齐的。
ip link show(或老一点的 ifconfig、netstat -i)会列出每个接口的 mtu。重点看三层:物理口、隧道口、容器网桥口。典型的问题配置是 eth0 mtu 1500、gre1 mtu 1500、docker0 mtu 1500,而物理路径实际只支持 1400——三个数全是"看起来很标准"的 1500,没有任何一个显式暴露问题。
顺手把 ip -d link show 隧道口 也看一眼,它能告诉你这是 GRE、IPIP、VXLAN 还是别的,从而对上前面那张封装开销表。
ip route show 的输出里,如果某条路由显式带了 mtu,那它优先于接口 MTU 生效。隧道场景下常见做法是给隧道路由单独打上 mtu:ip route change 10.8.0.0/24 dev gre1 mtu 1400。如果你发现接口 MTU 是 1500 但路由上挂着一个更小的 mtu,那说明有人已经处理过,问题可能出在另一半路径上。
内核为某个目的地学到的 PMTU 也会体现在这里,部分内核下 ip route get 目标 会带出缓存的 pmtu 值。这个值如果和实测不符(比如还是 1500),说明发送端的 PMTU 缓存是过期的,那正是黑洞的证据。
ss -i(建议 ss -ti)能看到每条 TCP 连接的内部状态,其中这几个字段是关键:
ESTAB 0 0 10.0.0.5:ssh 198.51.100.7:52344
cubic wscale:7,7 rto:204 rtt:1.8/0.9 mss:1460 pmtu:1500 rcvmss:536 advmss:1460 cwnd:10 ssthresh:8 retrans:0/12
接口、路由、MSS 这三个数都看过了,如果你想拿到铁证,就抓包。三步:
先看 ICMP need frag 有没有回。
tcpdump -ni any 'icmp[0] == 3 and icmp[1] == 4'
这个过滤条件精确匹配 ICMP Type 3 Code 4。发起一个大文件传输的同时跑这条命令,如果一个包都抓不到,而传输确实卡住了,那"PMTUD 被掐断"就是板上钉钉。如果能抓到,包里还会带上下一跳的 MTU 值,直接读出来用。别用 -ni any 抓错接口,隧道场景建议同时抓物理口和隧道口,对比"外层有没有收到、内层有没有透传"。
再看 SYN 里的 MSS 协商值。
tcpdump -ni any 'tcp[tcpflags] & tcp-syn != 0' -vv
抓下来会看到 mss 1460,sackOK,TS val ... 这样的选项串。如果你已经配了 MSS 钳位,这里应该看到被改写后的值(比如 1360);如果还是 1460,说明钳位规则没命中这条流——链路上挂错位置、只挂了单向、或者规则顺序被前面的 ACCEPT 抢先了,都得回头查。
最后看重传形态,把黑洞和拥塞区分开。
PMTUD 黑洞的典型抓包形态非常有辨识度:发送端反复重传同一个 seq 的大包,对端一个 ACK 都没有,也没有 dup ACK,更没有 window full。这和拥塞完全不同——拥塞时你能看到 dup ACK、快速重传、cwnd 收缩、RTT 抖动;黑洞时一切安静,只有同一段数据在原地打转。如果你在 ss -i 里看到 receive window 变成 0,那是另一类问题(应用层不读数据),别混为一谈。
到这一步,你已经知道真实路径 MTU(比如 1400)和该有的 MSS(1360)。下面四条路怎么选,取决于你能动到哪一层。
ip link set dev gre1 mtu 1400(Windows 是 netsh interface ipv4 set subinterface "以太网" mtu=1400 store=persistent)。这是最干净的做法:隧道口 MTU 降下来,上层 TCP 自动按 MSS 1360 协商,TCP 和 UDP 一起解决,不用管防火墙。
代价是影响面大且必须两端对齐。A 端改成 1400、B 端还是 1500,会出现单向异常,比原来更难查。而且这不是临时生效就算完——ip link set 重启即失效,必须写进网络配置(netplan 的 mtu:、NetworkManager 的 802-3-ethernet.mtu、/etc/network/interfaces 的 mtu 1400、systemd-networkd 的 [Link] MTUBytes=)。隧道重建、机器重启之后能不能保持,一定要验证。
还有一层影响要算进去:改接口 MTU 会波及所有走这个接口的流量,包括那些本来没问题的目的地。如果你的隧道只服务于特定网段,用路由 MTU(ip route ... mtu 1400)范围更小,优先于改接口。
原理是在 SYN 包经过防火墙时,改写 TCP 选项里的 MSS 值,让双方从建连那一刻起就用小 MSS 发包,压根不产生超限的大包。它只在三次握手时动一次 SYN,连接建立后不再插手,性能开销可以忽略。
iptables 写法:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360
nftables 写法:
nft add rule inet filter forward tcp flags syn tcp option maxseg size set 1360
两条命令的差别值得说清楚。--clamp-mss-to-pmtu 是按"出接口路由的 MTU"来算的,它不会自己去探测路径 MTU。如果你的隧道口 MTU 还挂着 1500,clamp 算出来还是 1460,等于什么都没做——这是 --clamp-mss-to-pmtu 最常见的"配了没效果"的原因。所以要么先把出接口/路由的 MTU 改对再 clamp,要么直接用 --set-mss 1360 写死数字。排查阶段我更倾向写死数字:结果确定、可验证、不依赖别处的配置。
MSS 钳位的边界,三条必须记住:
改完记得持久化:iptables-save > /etc/iptables/rules.v4 或 netfilter-persistent save,nftables 是 nft list ruleset > /etc/nftables.conf。
理论上,把 DF 去掉,让中间路由器分片,大包就能过去了。代价很实在:分片后的包在多数防火墙和 NAT 设备上会被丢弃或严重降级(很多设备不重组后续分片),分片导致吞吐下降、CPU 上升,而且分片本身还带来分片攻击的攻击面。这条路只在应急、且你能确认两端设备都能正常处理分片时短期用一下,不该作为长期方案。
Linux 内核有一套主动探测机制:
sysctl -w net.ipv4.tcp_mtu_probing=1
取值含义:0 关闭(多数发行版默认)、1 检测到疑似黑洞时才启用、2 始终启用。相关参数还有 net.ipv4.tcp_base_mss(探测起始 MSS,默认 512)和 net.ipv4.tcp_probe_threshold(默认 8,连续多少次失败后启动探测)。
它的价值是"在你完全管不了中间网络时的最后一道防线"——比如客户端散布在各地、你只能改自己这台服务器。但它有探测成本和延迟,稳态下不会主动用满带宽,所以正确的定位是兜底而不是主力。能改 MTU 就改 MTU,能做钳位就做钳位,探测留给确实够不着的地方。
顺带一提,QUIC / HTTP3 走的是 UDP,不受 MSS 钳位影响,但它有自己的 DPLPMTUD(RFC 8899)机制,不依赖 ICMP,靠主动发探测包来发现 MTU。所以同一个黑洞网络里,HTTP/3 站点往往比 HTTP/1.1 站点表现更好——如果你观察到"只有某几个站点正常、而且是支持 HTTP/3 的那几个",这条能帮你快速佐证判断。
"反正包大一点效率更高,直接上 jumbo frame 呗"——这是 MTU 话题里排名第一的反向操作。原因很简单但很硬:
巨型帧要求从源到目的整条二层路径上每一台设备都支持并启用 9000+ 的 MTU。交换机、路由器、网卡、虚拟交换机、防火墙、负载均衡、隧道端点,任何一跳不支持,超长帧就在那一跳被静默丢弃——注意是二层直接丢,连 ICMP 都不会有,因为以太网层根本没有"分片"和"不可达"这套机制。你把一个本来只是"部分业务卡"的问题,升级成"整个网段不通"。
更现实的是,公网路径上几乎不存在 9000 的 MTU。PPPoE 是 1492,大量运营商接入网是 1500,云厂商的 VPC 内部有些支持 9001 但一出 VPC 就打回 1500。你要真用上 jumbo,适用范围基本只有"同一个二层域内的服务器之间互访",比如存储网、计算集群的内部通信。跨机房、跨公网、跨隧道的场景,一律不要碰。
而且在隧道场景里,jumbo 根本不解决那个真问题:封装头吃掉的字节数是固定的,外层报文最终还是要走 1500 的物理链路。你把隧道口设成 9000,外层变成 9050,在物理口上一样发不出去。隧道口的 MTU 只能小于等于"物理路径 MTU − 封装开销",往大了改没有任何意义。
改完不等于好了,必须验证,而且要用真实业务验证,不能只看 ping。
ping -M do -s <MTU-28> 目标 应该稳定通,上一个台阶(-s 加 20)应该按预期失败。两个方向各测一遍。ss -ti 里 mss / advmss 应该是钳位后的值,pmtu 也应该对得上。scp 一个 200MB 文件、curl 那个之前加载一半的页面、跑一次批量入库。只看 ping 是不够的——ping 通而业务不通,正是我们一开始要解决的问题。-p icmp -j DROP 之前加一条 iptables -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT,云上安全组同理,只放这一个类型。别为了修 MTU 把整个 ICMP 敞开。如果你自己没有那么多窗口去试错,也可以把环境交给更熟悉的人。一万网络深耕 IDC 19 年(成立于 2007 年),深圳南山总部,自营机柜最快 1 分钟上架,提供裸金属、GPU 定制与一万云弹性云(¥25 起,以官网实时价为准)等多种形态,工程师可以协助核对宿主机—隧道—容器三层的 MTU 设置、帮忙看安全组是否误拦了 ICMP need frag,这类配置层面的排查本来就是服务商该做的活。真遇到跨网段、跨地域的隧道,BGP 多线与 CN2 GIA 回国链路上的 MTU 一致性,也需要有人从两端同时确认。
因为 ping 默认只发 56 字节载荷,整包不到 100 字节,它验证的是"小包能不能到",不是"网络能不能用"。网页要传 HTML、JS、图片、字体,稍大的资源单个报文就上千字节。你要复现真实情况,得用 ping -M do -s 1472 去测满载包。另一个可能是 DNS:域名解析走 UDP,大响应(开了 DNSSEC 的 TXT 记录)也会撞 MTU,表现为"域名解析有时候慢、有时候失败"。两者可以用 dig +bufsize=1400 区分。
会,而且非常常见。很多平台的安全组默认模板只给"放行全部 ICMP"或"全不放行"两个选项,选后者就等于掐断 PMTUD。更隐蔽的是"只放行 echo request/reply"这类细化模板——它让 ping 看起来正常,却把 Type 3 Code 4 挡在外面,故障更难察觉。正确做法是单独放行 ICMP Type 3 Code 4,其他类型继续拒绝。宿主机上的 iptables -p icmp -j DROP 同样致命,规则顺序上要保证 need frag 的 ACCEPT 在 DROP 之前。
ip link set dev eth0 mtu 1400 是立即生效、不用重启,但它不会持久化——重启网络服务或重启机器就会回到原值。要持久化就得写进配置文件:netplan 的 mtu:、NetworkManager 连接的 802-3-ethernet.mtu、interfaces 文件的 mtu 1400、systemd-networkd 的 MTUBytes=,各发行版写法不一样。改接口 MTU 会让该接口短暂中断,属于会影响业务的动作;MSS 钳位规则加载则基本无感,但同样要 iptables-save 或写进 nftables 配置。
几乎没有。它只在三次握手时改写一次 SYN 里的选项值,连接建立后就不再参与转发处理,不像 NAT 或深度包检测那样逐包开销。真正影响吞吐的是 MSS 值本身变小带来的额外包头占比:MSS 从 1460 降到 1360,有效载荷占比大概从 97% 降到 96%,在千兆以内完全感知不到。相比"大包全丢、连接挂死",这点损耗可以忽略。真正要注意的不是性能,是它只对 TCP、只对新建连接生效这两条边界。
三层都要看,但改的顺序是自上而下想清楚、自下而上动手。宿主机物理口/Underlay 的 MTU 是天花板,容器网桥和 veth 必须小于等于它减去封装开销。Docker 默认 docker0 是 1500,如果宿主机跑在 MTU 1450 的 VPC 里,容器就会中招——在 /etc/docker/daemon.json 里写 {"mtu": 1450} 然后重启 docker,注意已有容器要重建才生效。Kubernetes 更麻烦:Calico 的 VXLAN 模式要按 CALICO_IPV4POOL_MTU(或 ConfigMap 里的 veth_mtu)设成 Underlay−50,IPIP 模式减 20;Flannel 在 net-conf.json 里配 "MTU";Cilium 会自动探测但也可以显式指定。最容易漏的是 Pod 网络和宿主机网络走的是不同路径,两边要各测一次 tracepath。
三个原因叠加。一是去往不同目的地的路径不同,MTU 瓶颈可能在不同跳上,所以 A 站正常 B 站卡死——用 tracepath 分别测两个目的地,看到的 pmtu 往往不一样。二是不同站点的资源分片策略不同,图片切得碎的站点更容易"部分加载",单个大 bundle 的站点直接卡死。三是协议差异:支持 HTTP/3 的站点走 QUIC,靠 DPLPMTUD 自己探测,不依赖 ICMP,所以在同一个黑洞网络里反而能正常打开。这三条能解释绝大部分"选择性故障"。
不会让带宽变差。带宽是链路速率,和 MTU 是两个维度。MTU 变小意味着每个包的有效载荷占比略降,同样的数据要多发几个包,包速率和中断/CPU 开销略增。从 1500 降到 1400,理论开销增量在 1% 量级,实际测不出来。真正会让你变慢的是现在这个状态——大包全丢、不停重传、连接挂起,那才是零吞吐。用一句话讲:降 MTU 是"每个包少装 100 字节",不降是"大包全丢",这两个损失根本不在一个数量级。
按顺序查四件事。第一,钳位是不是真的命中了——tcpdump 抓 SYN 看 mss 选项有没有被改写,没改就是链挂错(该挂 FORWARD 挂成了 OUTPUT)或顺序被前面的规则抢走了。第二,是不是只做了单向——出向钳了、入向没钳,服务端下发大响应依然超限。第三,是不是存量长连接没重建——钳位只对新建连接生效,跑了几天的连接池还是老 MSS。第四,这个业务是不是根本不走 TCP——UDP、QUIC、SCTP 全都不吃 MSS 钳位,得靠降接口 MTU 或应用层处理。第四条最容易漏,尤其是上了 HTTP/3 之后。
本文涉及的封装开销(GRE 24、VXLAN 50、WireGuard 名义 32、ESP 传输模式 36–56、隧道模式再加 20 个新 IP 头)、MSS 换算关系、PMTUD 所依赖的 ICMP Type 3 Code 4、以及 Linux tcp_mtu_probing / tcp_base_mss / tcp_probe_threshold 等内核参数含义,均来自公开的协议标准与内核文档口径,命令与参数均为可直接执行的真实写法,未做任何虚构的实测或跑分。文中提到的一万网络相关服务能力、节点与价目(如一万云 ¥25 起、自营机柜最快 1 分钟上架、7×24 中文工单平均 5 分钟响应、硬件故障 10 分钟内自动迁移、免费系统盘每日 3 份快照、5–20G 免费防护、BGP 多线 + CN2 GIA 回国),以 https://www.idc10000.net/ 相应页面明示内容为准;涉及配置与报价的部分,具体以签约时最新报价与合同为准。文中场景为典型部署思路与故障推演,并非特指某一真实客户。
这类故障之所以难查,不是因为机理复杂,而是因为它骗过了所有常规健康检查,且全程不产生任何一条像样的错误日志。你只要记住一件事:连通性测试用小包,业务用大包,两者不是一回事。遇到"能连不能用",第一反应不该是加带宽、换线路、重启服务,而是敲一条 ping -M do -s 1472,或者干脆 tracepath 一次,把真实路径 MTU 这个数拿到手。
拿到数之后的选择就简单了:能改到隧道两端就降接口 MTU,只能动中间设备就做 MSS 钳位,两头都够不着就开 tcp_mtu_probing 兜底,同时把 ICMP Type 3 Code 4 单独放行。唯独把 MTU 往 9000 改这条,任何时候都别走——它不是解法,是把问题放大。至于 UDP 那一侧(QUIC、DNS、实时流),记住 MSS 钳位管不着它,要么降接口 MTU,要么让应用层自己分片。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品