ping命令持续发送少量互联网流量到远程地址并报告收到回应的总时间。如果流量因为网络故障或者错误配置而被丢弃,它也会报告。ping命令是最基本和初级的诊断网络问题的工具之一。
ping常被用来测试网络延迟,但是有时ping的延迟并不是网络引起的,所以为了正确理解ping的结果,有必要了解影响ping延迟的几个因素。
ping的原理是通过发送ICMP echo request包,在收到ICMP echo reply包之后,计算发送时间与接收时间之间的差值,得出延迟的时间。ping的输出举例如下:
ping缺省每秒发一个echo request,发包的时候不会输出任何信息,直至收到echo reply的时候才输出一条信息,格式如上,最后一列是延迟时间,ms表示毫秒。
影响ping延迟的因素主要有:
ping延迟包含了进程调度的延迟
由于ping本身是用户态的程序,它首先会受到进程调度的影响,比方说高优先级的进程与ping争抢CPU的话,ping的执行就会遭到拖延,这个调度延迟如果是发生在发包之后、收包之前,就会被计入ping的延迟之中。
多个同时运行的ping进程之间会互相干扰,导致延迟
ping通过raw socket发送和接收ICMP包,而raw socket不仅会收到给自己的包,也会收到给别人的包,假如有多个ping进程同时在运行,你的ping就有可能会收到别人的ping的echo reply,当然,ping程序可以从中挑出给自己的包,因为包里嵌入了对应的ping进程号,但是每个包都打开看看、并判断是不是给自己的——这都要消耗时间的,所以说,多个ping进程之间会互相干扰,导致延迟加大。不同的UNIX版本由于实现方式的差异,受这个因素的影响程度也不一样,比如HP-UX受影响较大,而Linux受影响相对较小,因为Linux采用了一种过滤机制:Linux Socket Filtering,亦即Berkeley Packet Filter (BPF),ping程序利用BPF给raw socket加上一个过滤器,这样内核会只把对应的echo reply传递给ping程序,给其他ping进程的echo reply不会再传给这个ping,避免了CPU和buffer资源的浪费,也减少了ping延迟。
其他类型的ICMP包也会对ping造成干扰
ICMP包有好几种类型,ping希望收到的是ICMP_ECHOREPLY,但是其他类型的包也都会传递给ping,我们上面说过,这是因为ping使用raw socket的缘故,raw socket会看到所有的ICMP包。ping需要消耗额外的时间和资源去查看这些本来不相干的包,故而有可能会产生延迟。以下列出各种ICMP包的类型供参考:
ICMP_ECHO
ICMP_ECHOREPLY
ICMP_SOURCE_QUENCH
ICMP_REDIRECT
ICMP_DEST_UNREACH
ICMP_TIME_EXCEEDED
ICMP_PARAMETERPROB
注1:在Linux上,虽然ping采用了BPF过滤机制,但是只过滤掉了发给其他ping进程的ICMP_ECHOREPLY包,其他类型的包是不过滤的,所以仍然会受到影响。
注2:在HP-UX上ICMP_SOURCE_QUENCH是最常见的影响ping延迟的因素。Source Quench是一种简陋的流控机制,当接收端有缓冲区满的时候,通过向发送端返回Source Quench,告知发送端降低发送速度,而满溢的缓冲区不一定与ICMP有关,更常见的事UDP的缓冲区。由于这种机制存在种种问题,有许多反对使用Source Quench的声音,比如:RFC6633。Linux从2.2起就不再支持ICMP Source Quench了。
还有些其它因素,比如网卡驱动,防火墙软件什么的,但比较少见,就不深入探讨了。
怎样判断ping延迟是网络延迟还是其它因素导致的呢?
如果有1秒以上的延迟的话,观察一下icmp_seq,它表示包的顺序,在下例中,第3个包的延迟是2.068秒,而第4个包的延迟只有0.183秒,如果发包的频率严格保持每秒一次的话,第4个包应该比第3个包先收到才对,而下例中,包的顺序并未颠倒,这说明第4个包的发送也被延迟了。发送延迟,那就不是网络延迟了,肯定有其它原因。
还有一个简单的方法可以一试,ping一下127.0.0.1或者ping本机的IP地址,它们不用通过网络,甚至不用进入网卡驱动程序,所以延迟应该非常小,可以作为一个基准值,如果它们的延迟比较大,那最大的可能是存在调度延迟或者ICMP包干扰之类的问题。