1、理解
网络延迟,即网络数据传输所用时间。这个时间可能是单向的,指从源地址发送到目的地址的单程时间;双向的,即从源地址发送到目的地址,然后又从目的地址发送回相应,这个往返全程的时间。
常用双向的往返通信延迟,比如 ping 的结果,就是 往返延时RTT(Round-Trip Time)。
ping 是基于 ICMP的,当禁用ICMP时,可以使用 hping3、traceroute
# -c 表示发送3此请求,-S表示设置 TCP SYN,-p表示端口号为80hping3 -c 3 -S -p 80 baidu.com

可以看到,往返延迟RTT,为37.7ms。
# --tcp表示使用TCP协议,-p表示端口号,-n表示不对结果中的IP地址执行反向域名解析traceroute --tcp -p 80 -n baidu.com

traceroute 会在路由的每一跳发送三个包,并在收到相应后,输出往返延时。如果无响应或超时响应(默认5s),就会输出一个星号。
2、分析
测试服务8080端口性能
wrk --latency -c 100 -t 2 --timeout 2 http://172.16.246.9:8080/
1、查看详情
抓取 8080 端口上手法的网络包,保存到 nginx.pacp
tcpdump -nn tcp port 8080 -w nginx.pcap
wrk 重新测试性能
wrk --latency -c 100 -t 2 --timeout 2 http://172.16.246.9:8080/
将生成的 nginx.pacp 使用 Wireshark 打开,使用图表查看
可以看到,第二次HTTP请求就变慢了,特别是客户端收到服务器第一个分组后,40ms才发出ACK响应(蓝色行)。这就是 TCP延迟确认(Delayed ACK)的最小超时时间。
这是针对 TCP ACK 的一种优化机制,也就是不用每次请求都发送一个 ACK,先等待一会(如 40ms),如果这段时间,正好有其他包需要发送,就带着ACK一起过去。如果超时没有,就单独发送ACK。
查询 TCP 文档。发现 ,只有TCP套接字专门设置了 TCP_QUICKACK,才会开启快去确认模式;否则,默认采用延迟确认机制。
可以使用 strace来查看 wrk 的套接字设置的TCP选项。
strace -f wrk --latency -c 100 -t 2 --timeout 2 http://172.16.246.9:8080/

可以看到,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 默认的延迟确认机制一起后,网络延迟会比较明显。
- 当 Server 发送了第一个分组后,由于 Client 开启了延迟确认,就需要等待 40ms 后才会回复 ACK
- 由于 Server 端开启了 Nagle,而这是没有收到第一个分组的 ACK,Server 也会一直等待
- 直到 40ms 超时后,Client 才会回复 ACK,然后,Server 才会继续发送第二个分组
TCP_NODEALY就会关闭 Nagle 算法。
可以看到实验中的 nginx 的 nagle 算法是禁用的。
