什么是延迟:拆解Ping的每个数字

list 文章目录

终端里敲一个 ping 命令,屏幕会回给你一串数字:64 bytes from 1.1.1.1: icmp_seq=0 ttl=57 time=12.3 ms。

这个 12.3ms 看着像个精确测量值——还带一位小数,透着一股确定感。可这 12.3ms 里到底装了什么?数据包在光纤里跑了多久?在路由器里排了多久的队?被防火墙查了多久?ping 一律不解释。

延迟不是单一物理量。它是一组完全不同性质的等待时间的总和。每一段都有不同的产生机制,不同的变化规律,不同的优化可能。把延迟当成一个整体来看待,和把“一辆车的成本”当成一个数字来讨论一样粗糙——是制造成本,还是使用成本,还是包含折旧和保险?不同的问题需要拆不同的分量。

延迟的四层构成

一个数据包从A到B再返回A所经历的时间,至少可以拆成四层。

传播延迟。电磁波在介质中传播需要时间。真空中的光速是每秒30万公里,光纤中的折射率大约1.50,实际传播速度约每秒20万公里。这意味着每1000公里的光纤距离,单向传播延迟约5ms,往返10ms。这个值由物理距离决定,无法压缩。北京到洛杉矶大约10000公里的大圆距离,传播延迟的下限在100ms左右(往返)。任何声称能把这个数字降到50ms以下的服务,在物理上不可能。它能降低的是别的分量。

队列延迟。数据包到达路由器时,如果出口接口正在发送其他数据包,新来的数据包必须在缓冲队列中等待。队列延迟不是固定的——它取决于链路利用率和缓冲区的深度。在低负载时,队列延迟接近零。当链路利用率超过80-90%时,队列延迟开始指数级增长。这种现象被称为“缓冲膨胀”(Bufferbloat),即过大的缓冲区掩盖了拥塞信号,导致TCP的拥塞控制无法及时响应,延迟飙升到几百甚至上千毫秒。队列延迟是四层构成中最容易变化、也最难预测的分量。

处理延迟。路由器需要检查数据包的头部,查找转发表,做出转发决策。这个时间在硬件转发设备上通常是微秒级(几十到几百微秒),在软件转发设备上可能达到毫秒级。对于大多数网络路径,处理延迟在每个跳点上的贡献很小,但如果路径经过了一个负载很重的软件防火墙、NAT网关或VPN端点,处理延迟就可能变得显著。

协议延迟。这一层和物理传输无关,和协议设计有关。TCP的三次握手需要1个RTT才能完成。TLS握手需要额外的1-2个RTT(取决于版本)。QUIC的0-RTT模式可以将这个代价降到0,但在实践中受限于重放攻击防护而并非总是可用。一个应用如果需要在传输数据前完成多次往返交互(比如HTTP/1.1的串行请求、MySQL的连接认证),协议延迟就会叠加。这些延迟不反映在ping的数字里——ping测量的是ICMP往返时间,不经过TCP握手,不涉及TLS。但用户实际感知的延迟包括了所有这些。

ping测量的是什么,不是什么

ping使用ICMP Echo Request和Echo Reply。这是一个在网络层运行的探测协议,不涉及传输层。大多数路由器对ICMP数据包的处理路径和TCP/UDP不同——ICMP数据包通常由路由器的控制平面处理,而不是数据平面的快速转发路径。

这意味着什么?ping测量的延迟可能不等于TCP数据包的延迟。在路由器负载较低时,这个差异可以忽略。但当路由器数据平面满载时,控制平面可能仍然能够及时响应ICMP请求(因为控制平面有独立的CPU资源和队列),导致ping显示延迟正常,而实际TCP流量已经在经历严重的队列延迟和丢包。

反向情况也存在:一些网络设备对ICMP流量设置了严格的速率限制。当ping频率较高时,部分ICMP请求被丢弃,ping报告丢包,但实际TCP流量的转发完全正常。这就是“ping丢包但应用不卡”的常见解释。

还有一个常被忽略的细节:ping测量的是往返时间(RTT),不是单向延迟。大多数网络路径的往返路径不对称——去程可能走一条路,回程走另一条。如果其中一条路径发生拥塞,RTT会升高,但你无法从ping的结果中判断是去程还是回程的问题。两个方向的路径可能由不同的ISP运营,经过不同的对等互联点,经历完全不同的网络条件。

bash
# ping只能告诉你RTT,不能告诉你去程和回程各占多少
ping -c 10 目标IP

# 要看路径不对称,需要traceroute分别看两个方向
# 但这需要目标端的配合——你在本地只能看去程路径
mtr -r -c 5 目标IP

时间变化:抖动不是噪声

连续ping一个目标,你会看到延迟数字在上下波动。9.2ms, 10.8ms, 8.7ms, 45.3ms, 9.1ms。

很多人会把这种波动视为“网络不稳定”,把那个45.3ms当作异常值忽略掉,关注平均值。但平均值在这里是一个危险的统计量。

那一个45.3ms的尖峰,可能是一个队列瞬间堆积的信号。它告诉你的信息比平均值多得多。如果尖峰有规律地出现——比如每10秒一次——可能对应某个路由器的缓冲区定期被填满。如果尖峰没有规律但幅度很大,可能是链路发生了间歇性拥塞,触发了TCP的重传超时。如果一个ping序列的标准差很大,即使平均值看起来不错,TCP的拥塞控制可能已经在频繁地削减窗口,有效吞吐量远低于链路带宽。

另一种时间模式是昼夜节律。晚高峰时段(本地时间20:00-23:00)的延迟普遍高于凌晨。这不是“网络坏了”,这是统计复用的必然结果——更多的人在使用共享的链路和节点。但节律的幅度值得关注。如果高峰延迟比低谷高出3倍以上,说明路径上存在严重的容量瓶颈。如果只高出10-20%,基本在正常波动范围内。

延迟与吞吐量的反直觉关系

有一个流传很广的误解:高延迟意味着低速度。

延迟和吞吐量(带宽)是两个正交的变量。一条链路的延迟是100ms,带宽是1Gbps,另一条链路的延迟是1ms,带宽是10Mbps。如果要传输一个10GB的文件,高延迟高带宽的链路远快于低延迟低带宽的链路——前者可以在约80秒内完成传输(受带宽限制),后者需要约8000秒(也受带宽限制)。

延迟影响的是“响应的快慢”,带宽影响的是“传输的快慢”。对于小文件、API请求、网页加载这类场景,延迟是主要矛盾。对于大文件下载、视频流、备份同步这类场景,带宽是主要矛盾。

但这里有一个TCP层面的耦合。TCP的吞吐量上限受延迟和丢包率的约束。在一个有丢包的链路上,TCP的拥塞窗口增长受RTT限制,实际吞吐量可能远低于链路带宽。这就是为什么高延迟高带宽的路径在传输大文件时也可能表现不佳——不是因为带宽不够,而是因为TCP的拥塞控制算法在长RTT下有更慢的恢复速度。这种现象在跨太平洋链路上很常见:iperf测出带宽充足,但实际文件传输速度受限于TCP的行为特征。

误判:游戏卡顿就是延迟高

游戏卡顿就是延迟高是一个误判

游戏玩家常说“延迟高”,但游戏体验中的“卡顿”不一定来自网络延迟。

游戏客户端在每个帧周期内需要完成:接收网络数据、更新游戏状态、渲染画面。如果某一帧的渲染时间过长(比如大量特效同时出现),即使网络数据已经到达,帧仍然会延迟显示。玩家感受到的“卡顿”可能是客户端性能问题,不是网络问题。游戏内显示的“ping”只测量网络往返时间,不知道渲染管线里发生了什么。

另一种情况是,游戏服务器本身的模拟频率(tick rate)限制了响应速度。一个tick rate为64Hz的服务器,每15.6ms才更新一次游戏状态。即使玩家的网络延迟是5ms,操作指令到达服务器后最多要等15.6ms才被处理。这部分延迟不在ping的测量范围内,但它直接贡献到“按下按键到看到效果”的总时间中。

区分网络延迟和客户端/服务端处理延迟的方式,不是看一个数字,而是观察不同场景下的行为一致性。如果卡顿只在特定场景出现(比如爆炸特效、大量玩家聚集),客户端性能是更可能的因素。如果卡顿与时间有关(晚高峰更严重),网络拥塞是更可能的因素。如果卡顿持续存在且与场景和时间都无关,服务端的处理延迟或tick rate限制更值得怀疑。

这个数字能做什么,不能做什么

ping的12.3ms是有用的,但它的有用建立在理解它不包含什么的前提下。

它不包含TCP握手。不包含TLS协商。不包含DNS解析。不包含应用层的序列化和反序列化。不包含服务端的业务处理。不包含客户端渲染。一个HTTP请求的端到端延迟可能比ping值高出几倍到几十倍,这在工程上是完全正常的,不是“网络有问题”。

同时,ping的12.3ms是路径上所有ICMP处理策略的妥协产物。它可能低估真实延迟(因为ICMP走了快速路径而TCP在排队),也可能高估真实延迟(因为ICMP被限速而TCP正常转发)。只有当你同时用TCP连接时间、应用层响应时间与ping做对比时,才能判断ping的数字在多大程度上代表了真实的数据平面行为。

延迟不是一个数字。它是一个剖面。不同层级的延迟由不同的机制产生,对不同的优化手段敏感。传播延迟是物理定律,无法优化。队列延迟是容量管理,可以通过增加带宽或改善队列策略优化。协议延迟是设计选择,可以通过协议升级或分段中继优化。理解了这个剖面,你才能在面对一个延迟问题时,知道该看什么,该忽略什么,以及那个ping的数字在多大程度上回答了你的问题,又在多大程度上误导了你。

作者

狗急加速器技术团队