1、理解

网络延迟,即网络数据传输所用时间。这个时间可能是单向的,指从源地址发送到目的地址的单程时间;双向的,即从源地址发送到目的地址,然后又从目的地址发送回相应,这个往返全程的时间。
常用双向的往返通信延迟,比如 ping 的结果,就是 往返延时RTT(Round-Trip Time)。
ping 是基于 ICMP的,当禁用ICMP时,可以使用 hping3traceroute

  1. # -c 表示发送3此请求,-S表示设置 TCP SYN,-p表示端口号为80
  2. hping3 -c 3 -S -p 80 baidu.com

image.png
可以看到,往返延迟RTT,为37.7ms。

  1. # --tcp表示使用TCP协议,-p表示端口号,-n表示不对结果中的IP地址执行反向域名解析
  2. traceroute --tcp -p 80 -n baidu.com

image.png
traceroute 会在路由的每一跳发送三个包,并在收到相应后,输出往返延时。如果无响应或超时响应(默认5s),就会输出一个星号。

2、分析

测试服务8080端口性能

  1. wrk --latency -c 100 -t 2 --timeout 2 http://172.16.246.9:8080/

image.png

1、查看详情

抓取 8080 端口上手法的网络包,保存到 nginx.pacp

  1. tcpdump -nn tcp port 8080 -w nginx.pcap

wrk 重新测试性能

  1. wrk --latency -c 100 -t 2 --timeout 2 http://172.16.246.9:8080/

将生成的 nginx.pacp 使用 Wireshark 打开,使用图表查看
image.png
可以看到,第二次HTTP请求就变慢了,特别是客户端收到服务器第一个分组后,40ms才发出ACK响应(蓝色行)。这就是 TCP延迟确认(Delayed ACK)的最小超时时间。
这是针对 TCP ACK 的一种优化机制,也就是不用每次请求都发送一个 ACK,先等待一会(如 40ms),如果这段时间,正好有其他包需要发送,就带着ACK一起过去。如果超时没有,就单独发送ACK。
查询 TCP 文档。发现 ,只有TCP套接字专门设置了 TCP_QUICKACK,才会开启快去确认模式;否则,默认采用延迟确认机制。
可以使用 strace来查看 wrk 的套接字设置的TCP选项。

  1. strace -f wrk --latency -c 100 -t 2 --timeout 2 http://172.16.246.9:8080/

image.png
可以看到,wrk只设置了 TCP_NODELAY 选项,而没有设置 TCP_QUICKACK。这说明 wrk 采用的正是延迟确认,也就解释了上面这个 40ms 的问题。

Nagle算法(纳格算法)

是TCP协议中,用于减小包发送数量的一种优化算法,目的是为了提高实际带宽的利用率。
比如,当有效负载只有 1 字节时,再加上 TCP头部和IP头部分别占用的 20 字节,整个网络包就是 41 字节,实际带宽的利用率只有2.4%(1/41)。如果整个网络带宽都被这种小包沾满,整个网络的有效利用率非常低。
Nagle 算法,通过和并TCP小包,提高带宽的利用率。
Nagle 算法规定,一个TCP连接上,最多只有一个未被确认的未完成分组;在收到这个分组的 ACK 前,不发送其他分组。这些小分组会被组合起来,并在收到 ACK 后,用同一个分组发送出去。
可以当与 Linux 默认的延迟确认机制一起后,网络延迟会比较明显。
image.png

  • 当 Server 发送了第一个分组后,由于 Client 开启了延迟确认,就需要等待 40ms 后才会回复 ACK
  • 由于 Server 端开启了 Nagle,而这是没有收到第一个分组的 ACK,Server 也会一直等待
  • 直到 40ms 超时后,Client 才会回复 ACK,然后,Server 才会继续发送第二个分组

TCP_NODEALY就会关闭 Nagle 算法。
image.png
可以看到实验中的 nginx 的 nagle 算法是禁用的。