直觉上,数据包从A到B经过的路由器越少,速度就该越快。大多数时候这个假设也确实成立——物理距离更短,传播延迟更低;跳数更少,处理开销更小。
然而在真实网络里,这个假设时常失灵。有种情况会反复上演: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跳。延迟数字显示,前几跳的RTT正常,但在某个中间节点之后突然跃升,而且波动剧烈。
这种情况通常会被直觉归因为“目标服务器变慢”。但在工程上,更值得怀疑的是路由变更引入了新的拥塞点。
可能的链条如下:
Stage 1: ISP调整了对上游提供商的BGP策略,选择了另一条更“短”的路径。这条路径可能通过一个更直接的对等互联点,减少了两跳。路由表收敛完成。从traceroute看,一切看起来更好了。
Stage 2: 这条新路径的出口节点接口带宽有限。原路径虽然跳数多,但经过了多个负载均衡的链路。新路径的所有流量现在都涌向同一个拥塞点。出口缓冲队列开始变长。
Stage 3: TCP流经这个拥塞点时,开始出现间歇性丢包。丢包触发发送端的拥塞控制机制,拥塞窗口被削减。对于用户来说,这不是持续的低速率,而是“卡顿”——某些TCP段快速通过,然后发生重传超时,应用层等待,然后再加速,再丢包。
Stage 4: 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可能使用了完全不同的出口策略和提供商,避开了那个拥塞的对等点。表面上是切换网络解决了问题,实际上是切换了出口路径。这个区别在工程上很重要,因为它决定了后续的判断方向——是排查本地网络,还是理解出口路由?
如果要确认这一点,需要一个不受本地ISP出口策略影响的测量点。比如从云主机向同一目标发起测量,并比较二者的TCP行为差异。
# 在本地运行 mtr -r -c 10 -n 目标IP tcptraceroute 目标IP 443 # 在云主机上同时运行相同的命令 # 如果云主机的路径跳数更多但延迟更低,说明本地ISP的短路径存在拥塞
这种比较的价值不在于找到“正确答案”,而在于建立对照基线。有了基线,才能判断某个现象是局部的还是全局的,是路径选择问题还是容量问题。
建立判断框架
要区分路径缩短带来的拥塞问题和其他类型的延迟问题,有几个信号可以参考,但没有一个信号是决定性的。
时间模式是一个起点。如果延迟恶化呈现明显的昼夜节律,且与本地用户的活跃时间吻合,那么出口拥塞的可能性更高。如果延迟恶化是突然发生且持续不变,那么路由策略变更或物理链路故障的可能性更高。
MTR的中间跳延迟分布需要仔细解读。如果延迟的增长不是渐进式,而是在某个单一跳之后出现阶跃式跃升,并且该跳之后的每一跳都维持在这个高值附近,那么这一跳很可能是一个出口节点,且发生了队列堆积。而如果延迟的增长是渐进式的,每一跳都增加一点,那么更可能是物理距离的贡献。
很多人会试图通过改变DNS来解决问题。在一些情况下这有效,但机制容易被误解。改变DNS改变了目标服务器的IP地址,这个新IP可能通过不同的路径可达。如果新路径绕过了原来的拥塞出口节点,延迟改善。这不是DNS“快”,而是IP路径不同。反之,如果新IP仍然经过同一个拥塞点,那么延迟不会改善。将问题定义为“DNS问题”是一种误判;它是路径可达性问题,只是被DNS变更触发了。
还有一种情况是,网络优化服务通过私有骨干网绕过了公共互联网的拥塞点。用户看到traceroute路径变长(因为增加了隧道跳数),但延迟反而下降。这与我们讨论的情况正好相反,但原理是一致的:拓扑跳数和性能之间没有必然联系。跳数更少并不一定更好,跳数更多也不一定更差。
在判断时,一个可操作的步骤是:观察从不同源IP到同一目标的路径和延迟。如果所有源IP在通过同一个AS边界后都出现延迟跃升,那么那个AS的出口策略或对等容量很可能是主要矛盾。如果只有你的ISP出现这个问题,那么就是你本地ISP的出口选择问题。
留白
这个系统没有单一原因。网络是一个统计复用、分布式决策的概率系统。路由协议关注可达性,不关注性能。TCP关注拥塞信号,不关注路由。它们各自在自己的层面做出局部最优决策,全局行为因此涌现。
路径变短但延迟变高,这个现象只是这种涌现行为的一个具体表现。上面给出的几个命令,不是为了“解决问题”,而是为了建立观察系统的不同视角。当你同时看到控制平面的路径、数据平面的TCP行为、以及来自另一个网络基线的对照数据时,你对“网络为什么慢”这个问题的理解,会从猜测进入测量。
而测量的第一步,是承认你当前看到的数字可能正在误导你。