直觉上,数据包从A到B经过的家里路由越少,速度就该越快。通常数时候这个假设也确实成立——物理距离更短,传播ping 值更低;跳数更少,处理开销更小。
然而在真实网络里,这个假设时常失灵。有种情况会反复上演:traceroute 里路线跳数变少了,应用的响应时间反倒变长。表面看这是矛盾,真用起来它恰好暴露了互联网路由机制与传输机制之间的脱节。
这不是一个要看“修复”的问题。它是一个要看在结构层面被理解的行为。
路由表的幻觉
当你运行traceroute或MTR时,你看到的只是从你到目标的一条单向路线。客户端软件显示的是每个中间节点的IP地址和响应时间,这让它看起来像是在测量网络性能。
但它测量的是控制平面,不是数据平面。
BGP负责决定数据包如何穿越自治系统之间的边界。当BGP做出一次路由变更时——比如起因某个对等互联点的链路down掉,或起因某个ISP调整了本地优先级——路由表会收敛到一个新的拓扑状态。这个新状态可能确实包含更少的AS跳数。
但是,更少的AS跳数只是拓扑距离的缩短。它不承诺带宽资源充足,不承诺缓冲排着队浅,也不承诺包丢失率低。在新的路线上,某个拥塞的交换点或某个过载的出海出口家里路由,就足以抵消所有路线缩短带来的好处。
更关键的是,路由变更本身可能带来瞬时的性能损伤。BGP收敛期间,家里路由可能要看额外的时间来重建转发表,在此期间数据包可能被以较低优先级处理。这意味着,一个人刚刚观察到traceroute路线变短时,恰恰是路线最容易卡顿的时候。
在工程上,要区分控制平面信息和数据平面行为,一个直接的办法是同时收集两边的数据,而不是只看MTR的汇总输出。
# 一边持续记录路线变化,一边测量实际TCP连接建立时间 while true; do echo "=== $(date +%H:%M:%S) ===" mtr -r -c 5 -n 1.1.1.1 2>/dev/null curl -s -o /dev/null -w "TCP connect: %{time_connect}s, TTFB: %{time_starttransfer}s\n" https://cloudflare.com/cdn-cgi/trace sleep 60 done
这样做的目的不是找到“哪个跳出了问题”,而是观察路线变化与连接建立时间之间的相关性——或者说,观察它们之间惊人的缺乏相关性。路由跳数减少但time_connect上升的场景,正是路线缩短而拥塞加剧的信号。
行为链:一个常见的场景

假设用户通过狗急加速器访问一个外国应用。在某一天,用户发现响应变慢,于是运行MTR,意外地发现路线跳数比昨天还少了3跳。ping 值数字显示,前几跳的RTT正常,但在某个中间节点之后突然跃升,而且波动剧烈。
这种情况通常会被直觉归起因“目标服务器变慢”。但在工程上,更值得怀疑的是路由变更引入了新的拥塞点。
可能的链条如下:
Stage 1: ISP调整了对上游提供商的BGP调度规则,选择了另一条更“短”的路线。这条路线可能通过一个更直接的对等互联点,减少了两跳。路由表收敛完成。从traceroute看,一切看起来更好了。
Stage 2: 这条新路线的出海出口节点接口带宽资源有限。原路线虽然跳数多,但经过了多个负载均衡的链路。新路线的所有流量现在都涌向同一个拥塞点。出海出口缓冲排着队开始变长。
Stage 3: TCP流经这个拥塞点时,开始出现间歇性包丢失。包丢失触发发送端的拥塞控制机制,拥塞窗口被削减。对于用户来说,这不是持续的低速率,而是“卡顿”——某些TCP段快速通过,然后发生丢过来重写超时,应用层等待,然后再加速,再包丢失。
再看第四阶段:MTR 最后一跳丢包率不高,中间某跳却显示 5% 丢包,有人就以为是这个中间节点有问题。其实是中间节点的控制平面在限速,丢掉的是探测包,属控制平面策略,与转发平面的拥塞无关。真正发生在转发平面的丢包在出口节点之后;而出口节点又可能优先处理探测包,反而把问题掩盖了。
要看到转发平面的真实行为,要看发送TCP数据流而不是ICMP探测包。以下片段用hping3模拟一个带数据的TCP连接,观察SYN包的丢过来重写行为——这是比MTR包丢失率更可靠的拥塞信号:
# 向目标80端口发送SYN包,如果3秒内无响应则丢过来重写 # 丢过来重写次数暗示了路线上的拥塞程度 hping3 -S -p 80 -c 20 -W 3 目标IP
如果观察到持续的SYN丢过来重写,而同时MTR显示路线跳数很少且中间节点包丢失率低,那几乎能确定问题出在转发平面的拥塞,而不是控制平面能看到的任何东西。
出海出口调度规则与拥塞的隐蔽性
ISP的出海出口调度规则是这个系统中最不透明的变量之一。一个ISP可能有多个上游提供商,同时也有多个对等互联点。它在选择出海出口时,不仅考虑AS路线长度,还考虑商业成本——比如通过某个对等互联点发送流量可能比通过付费的上游提供商更便宜。
这意味着,当一条路线变短时,这很可能不是起因ISP在优化性能,而是起因ISP在优化成本。
另外要注意成本驱动的选路:夜间低谷时往往正常,到了峰值时段却会引入严重拥堵。用户看到的症状因此有明显时段特征——上午正常,下午变慢。这常被误认为是目标服务负载高或本地 Wi-Fi 干扰,但更可能是出口节点在特定时间撞到了容量上限。
由此还衍生出更难识破的误判:换一个网络后问题消失,于是更确信’原网络有问题‘。可另一个网络的运营商可能用了完全不同的出口策略和上游,正好绕开了那个拥堵的对等点。表面是换网络解决了问题,实际是换了出口路径。这个区别很重要,它决定了下一步:是排查本地网络,还是去理解出口路由。
如果要确认这一点,要看一个不受本地ISP出海出口调度规则影响的测量点。比如从云主机向同一目标发起测量,并比较二者的TCP行为差异。
# 在本地运行 mtr -r -c 10 -n 目标IP tcptraceroute 目标IP 443 # 在云主机上同时运行相同的命令 # 如果云主机的路线跳数更多但ping 值更低,说明本地ISP的短路线存在拥塞
这种比较的价值不在于找到“正确答案”,而在于建立对照基线。有了基线,才能判断某个现象是局部的还是全局的,是路线选择问题还是容量问题。
建立判断框架
要区分路线缩短带来的拥塞问题和其他类型的ping 值问题,有几个信号能参考,但没有一个信号是决定性的。
时间模式是一个起点。如果ping 值恶化呈现肉眼可见的昼夜节律,且与本地用户的活跃时间吻合,那么出海出口拥塞的可能性更高。如果ping 值恶化是突然发生且持续不变,那么路由调度规则变更或物理链路故障的可能性更高。
读 MTR 中间跳的延迟分布要看仔细:如果延迟不是渐进增长,而是在某一跳之后阶跃式跃升,后面每一跳都维持在这个高值附近,那一跳很可能是出口节点,正在堆积队列。如果是逐跳渐进增加、每跳加一点,那更可能是物理距离的贡献。
遇到这种情况,很多人会先改 DNS。有时确实有效,但机制常被讲错:改 DNS 换的是目标服务器解析出的 IP,而这个新 IP 未必还走原来的路。如果新路径绕开了那个堵住的出口节点,延迟就改善了——不是 DNS 变’快‘,而是走的路不同。反过来,若新 IP 还是从同一个堵点出去,延迟一点也不会变。把它叫’DNS 问题‘是误判,本质是可达性问题,DNS 改动只是把它触发出来。
还有一种相反的情况:网络优化服务用私有骨干网绕开公网的拥堵点。用户看到 traceroute 跳数变多(隧道多了几跳),延迟却下降。这与前面说的方向相反,但原理一致:跳数和性能没有必然联系——跳得少不一定更好,跳得多也不一定更差。
在判断时,一个可操作的几步是:观察从不同源IP到同一目标的路线和ping 值。如果所有源IP在通过同一个AS边界后都出现ping 值跃升,那么那个AS的出海出口调度规则或对等容量很可能是主要矛盾。如果只有你的ISP出现这事儿,那么就是你本地ISP的出海出口选择问题。
留白
这个系统没有单一原因。网络是一个统计复用、分布式决策的概率系统。路由协议关注可达性,不关注性能。TCP关注拥塞信号,不关注路由。它们各自在自己的层面做出局部最优决策,全局行为这样看来涌现。
’路径变短、延迟反而变高‘,只是这类涌现行为的一个具体例子。前面那些命令,目的不是’直接解决‘,而是帮你建立不同的观察角度。当你同时看到控制平面的路径、数据平面上 TCP 的表现,以及另一条网络的对照数据,对’网络为什么慢‘的理解才会从猜测走向测量。
而测量的第一步,是承认你当前看到的数字可能正在误导你。