其他原因导致的网络延迟:
1)网络传输慢,导致延迟;
2)Linux 内核协议栈报文处理慢,导致延迟;
3)应用程序数据处理慢,导致延迟等等。
网络延迟
1)这个时间可能是单向的,指从源地址发送到目的地址的单程时间;
2)也可能是双向的,即从源地址发送到目的地址,然后又从目的地址发回响应,这个往返全程所用的时间
通常,我们更常用的是双向的往返通信延迟,比如 ping 测试的结果,就是往返延时 RTT(Round-Trip Time)。
应用程序延迟
从应用程序接收到请求,再到发回响应,全程所用的时间。也指的是往返延迟,是网络数据传输时间 加上 数据处理时间 的和。
获取网络延迟
可以使用 ping traceroute hping3 来获取网络延迟:
hping3
# hping3 -c 3 -S -p 80 baidu.com HPING baidu.com (eth0 123.125.115.110): S set, 40 headers + 0 data bytes len=46 ip=123.125.115.110 ttl=51 id=47908 sport=80 flags=SA seq=0 win=8192 rtt=20.9 ms len=46 ip=123.125.115.110 ttl=51 id=6788 sport=80 flags=SA seq=1 win=8192 rtt=20.9 ms len=46 ip=123.125.115.110 ttl=51 id=37699 sport=80 flags=SA seq=2 win=8192 rtt=20.9 ms --- baidu.com hping statistic --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 20.9/20.9/20.9 ms // -c 表示发送3次请求,-S 表示设置 TCP SYN,-p 表示端口号为 80 // 从 hping3 的结果中,你可以看到,往返延迟 RTT 为 20.9ms
traceroute
# traceroute --tcp -p 80 -n baidu.com traceroute to baidu.com (123.125.115.110), 30 hops max, 60 byte packets 1 * * * 2 * * * 3 * * * 4 * * * 5 * * * 6 * * * 7 * * * 8 * * * 9 * * * 10 * * * 11 * * * 12 * * * 13 * * * 14 123.125.115.110 20.684 ms * 20.798 ms // --tcp表示使用TCP协议,-p表示端口号,-n表示不对结果中的IP地址执行反向域名解析
第一步、创建负载环境
# docker run --network=host --name=nginx-good -itd nginx # docker run --network=host --name=nginx-latency -itd feisky/nginx:latency // 测试 Nginx 服务已经启动 # curl http://10.10.50.199 # curl http://10.10.50.199:8080 // 测试两个主机的延迟 # hping3 -c 3 -S -p 80 10.10.50.199 ... len=44 ip=10.10.50.199 ttl=64 DF id=0 sport=80 flags=SA seq=2 win=29200 rtt=7.6 ms ... # hping3 -c 3 -S -p 8080 10.10.50.199 ... len=44 ip=10.10.50.199 ttl=64 DF id=0 sport=8080 flags=SA seq=1 win=29200 rtt=7.6 ms ...
第二步、测试 Nginx 性能
对于 80 端口的 Nginx 服务:
# wrk --latency -c 100 -t 2 --timeout 2 http://10.10.50.199/ Running 10s test @ http://10.10.50.199/ 2 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 9.19ms 12.32ms 319.61ms 97.80% Req/Sec 6.20k 426.80 8.25k 85.50% Latency Distribution 50% 7.78ms 75% 8.22ms 90% 9.14ms 99% 50.53ms 123558 requests in 10.01s, 100.15MB read Requests/sec: 12340.91 Transfer/sec: 10.00MB
对于 8080 端口的 Nginx 服务:
# wrk --latency -c 100 -t 2 --timeout 2 http://10.10.50.199:8080/ Running 10s test @ http://10.10.50.199:8080/ 2 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 43.60ms 6.41ms 56.58ms 97.06% Req/Sec 1.15k 120.29 1.92k 88.50% Latency Distribution 50% 44.02ms 75% 44.33ms 90% 47.62ms 99% 48.88ms 22853 requests in 10.01s, 18.55MB read Requests/sec: 2283.31 Transfer/sec: 1.85MB
很明显,8080 端口的 Nginx 性能弱于 80 端口的 Nginx 服务。
第三步、问题排查,分析流量
// 在远程主机中运行抓包命令 # tcpdump -i "ens160" -nn tcp port 8080 -w nginx.pcap // 在本地主机执行性能测试 # wrk --latency -c 100 -t 2 --timeout 2 http://10.10.50.5:8080/
把抓取到的 nginx.pcap 复制到 Wireshark 进行分析:
1)选中某个 HTTP 数据包,右键,Follow TCP Stream,这样显示某个流中的数据包,而不是所有连接的数据包
2)打开流图,更直观查看数据包:Statics => Flow Graph => Displayed packets / TCP Flows / Standard source …
客户端的延迟确认
看到 40ms 这个值,我们可以猜测这是 TCP 延迟确认(Delayed ACK)导致的,因此 40ms 是最小超时时间。
我们要检查客户端是否开启延迟确认,就要看客户端开启哪些连接选项:
# strace -f wrk --latency -c 100 -t 2 --timeout 2 http://192.168.0.30:8080/ ... setsockopt(52, SOL_TCP, TCP_NODELAY, [1], 4) = 0 ...
只有开启 TCP_QUICKACK 选项才会禁用 延迟确认。也就是说这里确实启用延迟确认。
服务端的 Nagle 算法
虽然客户端会延迟确认,但是并不会影响服务端发送数据包,也就是说响应不会很久。但是从图中可以看出,在客户端发送 ACK 之后,服务端才发送其他数据。
数据包 1720 与 1265 的 ACK 是相同的,他们是在 1719 之后才发送的。此时我们可以猜想服务端开启 Nagle 算法(纳格算法)
但是在延迟确认的基础上,二者配合会导致延迟明显:客户端的 ACK 在等待”顺风车“,而服务端收不到 ACK,由于 Nagle 算法会继续等待,这样服务端也无法响应。
检查 服务端的 Nginx 是否开启 tcp_nodelay 选项,将其设置为 on 即可解决问题。
参考文献