这篇文章上次修改于 899 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

ping 工具可用来定位网络延迟问题,当 ping 本身也出现了问题时,需要抓取 ping 命令的收发包,进行分析并找出问题原因。

tcpdump 和 Wireshark 是常用的网络抓包工具:

  • tcmdump 仅支持命令行格式,常用在服务器端。
  • Wireshark 除了抓包外,还提供界面和汇总分析工具。

安装:

$ sudo apt install tcpdump wireshark

1 现象

# ping 3 次(默认每次发送间隔1秒)
$ ping -c3 geektime.org
PING geektime.org (35.190.27.188) 56(84) bytes of data.
64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=1 ttl=43 time=36.8 ms
64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=2 ttl=43 time=31.1 ms
64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=3 ttl=43 time=31.2 ms

--- geektime.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 11049ms
rtt min/avg/max/mdev = 31.146/33.074/36.809/2.649 ms

可以看懂,。3 次发送,收到 3 次响应,没有丢包,但三次发送和接受的总时间居然超过了 11s(11049ms)。

2 排查

查看是否是 DNS 解析问题:

$ time nslookup geektime.org
Server:        127.0.0.53
Address:    127.0.0.53#53

Non-authoritative answer:
Name:    geektime.org
Address: 35.190.27.188


real    0m0.018s
user    0m0.006s
sys    0m0.000s

域名解析还是很快的,只需要 18ms。

打开另一个终端,采用 tcpdump 抓包,并且在之前的终端重新执行 ping.

# -nn 不解析抓包中的域名、端口号和协议
# udp port 53,只显示 udp 端口号为 53 的包,包括源端口和目的端口
# host 35.190.27.188,只显示 IP 为 35.190.27.188 的包,包括源 IP 和目的 IP

$ tcpdump -nn udp port 53 or host 35.190.27.188

cpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:02:31.100564 IP 172.16.3.4.56669 > 114.114.114.114.53: 36909+ A? geektime.org. (30)
14:02:31.507699 IP 114.114.114.114.53 > 172.16.3.4.56669: 36909 1/0/0 A 35.190.27.188 (46)
14:02:31.508164 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 1, length 64
14:02:31.539667 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 1, length 64
14:02:31.539995 IP 172.16.3.4.60254 > 114.114.114.114.53: 49932+ PTR? 188.27.190.35.in-addr.arpa. (44)
14:02:36.545104 IP 172.16.3.4.60254 > 114.114.114.114.53: 49932+ PTR? 188.27.190.35.in-addr.arpa. (44)
14:02:41.551284 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 2, length 64
14:02:41.582363 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 2, length 64
14:02:42.552506 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 3, length 64
14:02:42.583646 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 3, length 64
  • 第 1 条,表示发往 114.114.114.114 的 A 记录查询请求。

    • 36909+ 是查询标识,+ 表示启动递归查询。
    • A? 表示查询 A 记录。
    • 30 表示报文长度。
  • 第 2 条,返回 DNS 响应。
  • 第 3、4 条,分别为 ICMP echo request 和 ICMP echo reply,时间戳相减为 ICMP 所需时间,为 30ms,没有问题。
  • 第 5、6 条,为反向地址解析请求,即从 IP 反查域名。没有响应包,且都是超时 5s 后才发出下一条请求。
  • 后面的 4 个包是两个正常的 ICMP 请求,耗时正常。

所以,是 PTR 有问题,并不是所有的 IP 都会定义 PTR 记录。禁调 PTR 即可:

$ ping -n -c3 geektime.org
PING geektime.org (35.190.27.188) 56(84) bytes of data.
64 比特,来自 35.190.27.188: icmp_seq=1 ttl=107 时间=48.0 毫秒
64 比特,来自 35.190.27.188: icmp_seq=2 ttl=107 时间=47.1 毫秒
64 比特,来自 35.190.27.188: icmp_seq=3 ttl=107 时间=47.8 毫秒

--- geektime.org ping 统计 ---
已发送 3 个包, 已接收 3 个包, 0% 包丢失, 耗时 2002 毫秒
rtt min/avg/max/mdev = 47.126/47.623/47.972/0.361 ms

现在只需要耗时 2s 即可。

但是 tcpdump 的输出不太规整,可以先将其输出保存下来:

$ tcpdump -nn udp port 53 or host 35.190.27.188 -w ping.pcap

然后采用 Wireshark 打开,不仅以更规整的格式,展示了各个网络包的头部信息;还用了不同颜色,展示 DNS 和 ICMP 这两种不同的协议。你也可以一眼看出,中间的两条 PTR 查询并没有响应包。

参考

倪朋飞. Linux 性能优化实战.