一、从“偶发中断”的感官切入
你可能经常遇到这种情况:自己做的网站绑定了CDN后,偶尔会有用户反馈“图片加载不出来”“视频卡成PPT”,但你盯着CDN的监控后台,带宽、延迟、丢包率这些指标全都是绿的,没任何异常。或者你作为运维,测试源站到CDN节点的联通性,大部分时候都没问题,偶尔跑几次 traceroute 就会出现几个星号,过会儿又好了。这种时好时坏的偶发性中断,是很多人头疼的问题,今天我们就从最基础的 traceroute 开始,一步步找到藏在里面的 MTU 分片问题,彻底搞定这类故障。
二、第一步:用traceroute“追踪断线的脚印”
traceroute其实就是给网络包做“脚印追踪”,你从源站发出去的每一个包,路过的每一个路由节点都会给你回个消息,告诉“我在这里”,如果中间某个节点没回,就说明这里可能丢包了。但偶发问题的关键在于“路过的节点没回”不是永久的,可能这次回了,下次就没回,所以我们不能只跑一次 traceroute,要多跑几次找规律。
2.1 重复触发traceroute找“波动的节点”
很多人第一次遇到 traceroute 有星号,就直接认定中间节点出问题了,但其实偶发的星号大概率不是节点挂了,而是某个节点的处理能力波动,或者包的大小刚好超过了某个限制。我们可以写个简单的脚本,循环跑 traceroute,比如跑30次,每次间隔1秒,这样就能把偶尔丢包的节点揪出来。下面是Linux/macOS下的示例代码:
#!/bin/bash
# 目标换成你的CDN节点IP,比如111.22.33.44
TARGET_IP="111.22.33.44"
# 循环30次,每次跑traceroute
for i in {1..30}
do
echo "=== 第$i次 traceroute 结果 ==="
traceroute $TARGET_IP
# 每次间隔1秒,避免请求太密集
sleep 1
done
把这个脚本保存成 traceroute_test.sh,执行后你会看到,某几行的节点偶尔会出现星号,而其他时候是正常的,那这个节点就是我们要重点关注的“波动点”。
三、traceroute里的“星号”藏着什么?
你可能会问,为什么同一个节点,有时候回消息,有时候不回?很多人第一反应是“网络波动”,但更深层的原因,往往是网络包的大小问题。traceroute 默认用 UDP 包,而且包的大小是固定的,如果这个包的大小超过了中间节点或CDN节点的最大允许尺寸,节点就会处理失败,要么不回消息,要么直接丢包,显示成星号。这时候我们就需要搞清楚那个“最大允许尺寸”是什么,也就是MTU。
四、MTU:被忽略的“包大小天花板”
MTU是个专业名词,我们不用记全称,就理解成“网络里每个节点允许通过的最大包裹尺寸”。比如你寄快递,快递公司规定每个包裹不能超过1.5KB,超过的话就得拆成两个包裹,这就是“分片”。路由节点就像快递公司,如果你发的包超过了某个节点的MTU,节点要么把包拆成小的再发,要么直接把包丢了——如果节点忙的时候,就会选择直接丢包,这就造成了偶发的中断。
4.1 用ping测路径MTU的临界值
怎么知道源站到CDN节点之间的路径MTU是多少?最实用的方法是用ping命令,ping可以设置包的大小,还能要求包“不分片”,这样就能测最大的能通过的包大小。下面是Linux下的示例代码,用来测到刚才那个CDN节点的路径MTU:
#!/bin/bash
# 目标换成你的CDN节点IP
TARGET_IP="111.22.33.44"
# 初始包大小设为1472(IP头28字节+ICMP头8字节,总共1500字节,对应默认MTU)
packet_size=1472
# 循环缩小包大小,直到ping通(不分片)
while true
do
# -M do表示禁止分片,-s指定包大小,-c1只发1个包
ping -M do -s $packet_size -c 1 $TARGET_IP > /dev/null 2>&1
if [ $? -eq 0 ]
then
# 计算实际MTU:包大小+IP头+ICMP头
actual_mtu=$((packet_size + 28 + 8))
echo "当前路径最大MTU为:$actual_mtu"
break
else
# 步长设为100,可根据需求调整,步长越小结果越精准
packet_size=$((packet_size - 100))
if [ $packet_size -lt 0 ]
then
echo "路径MTU异常过小,请检查网络联通性"
break
fi
fi
done
这个脚本执行后,会告诉你源站到CDN节点之间的路径MTU是多少。比如最后测出是1420,那说明这个路径最大能通过的包大小是1420,对应的MTU就是1420。这时候如果源站的MTU是默认的1500,发出去的1500包就超过了路径MTU,需要分片,忙的时候就会丢包,导致偶发中断。
4.2 为什么偶发中断偏偏是MTU的锅?
这是因为分片的不确定性:当网络负载低的时候,中间路由节点有足够的资源来处理分片,不管包多大,拆成小的就能正常通过;当网络负载高的时候,路由节点忙着处理其他包,就会跳过分片处理,直接把超过MTU的包丢了,所以就出现了“有时候好,有时候坏”的偶发情况。很多时候这种问题发生在CDN节点,因为CDN本身有很多节点,不同节点的路径MTU可能不一样,某个节点的路径MTU刚好和源站不匹配,就会偶尔出问题。
五、排查的完整流程和注意事项
遇到源站到CDN的偶发联通中断,不用急着找运营商,按以下步骤来就能搞定:
- 多跑几次traceroute:找到偶尔丢包的节点,别被一次结果误导;
- 测路径MTU:用刚才的ping脚本找到路径的最大包大小,对比源站的MTU设置;
- 调整MTU:如果源站的MTU比路径MTU大,就把源站的MTU改成路径MTU的值,或者加几个字节留余量。
5.1 常见的踩坑点
第一个坑是Windows和Linux的ping参数不一样:Windows下ping不分片的参数是-f,包大小参数是-l,比如ping -f -l 1472 111.22.33.44,别用Linux的参数,不然测出来的结果完全不对;
第二个坑是忽略中间节点的MTU:路径上的每个路由节点都有自己的MTU,比如源站MTU1500,中间某个节点MTU1400,那整个路径的MTU就是1400,不是源站的1500;
第三个坑是CDN节点的防火墙拦截分片包:有些CDN节点的防火墙会拦截超过某个大小的分片包,这时候就算路径MTU够,也可能丢包,要检查CDN的防火墙规则。
5.2 实际案例的验证
之前我帮一个电商客户排查过这个问题:他们的CDN是阿里云的,源站用的是腾讯云的云服务器,偶尔有用户反馈商品图片加载失败,CDN监控全绿,traceroute偶尔有星号。后来按刚才的脚本跑traceroute,发现第5跳(腾讯云到阿里云的节点)偶尔丢包,然后测路径MTU,发现这个跳的MTU是1420,源站的MTU默认是1500,把源站的MTU改成1420后,再也没出现过偶发的图片加载问题。
六、总结
源站与CDN节点之间的偶发性联通中断,看似复杂,其实大部分时候都是MTU不匹配导致的分片丢包问题。不用纠结那些晦涩的专业术语,就把MTU当成快递的最大包裹尺寸,分片当成拆包裹,就能轻松理解整个问题的逻辑。排查的时候从最基础的traceroute和ping入手,多重复几次避免误判,找到问题的根源后,只要调整一下MTU设置,就能彻底解决这类偶发故障,保障用户的访问体验。
评论
围绕“源站与CDN节点之间联通性偶发性中断:从traceroute到MTU分片问题的排查路由”参与讨论