当前位置: 首页 > 科技观察

Linux网络延迟故障排除

时间:2023-03-12 14:17:08 科技观察

在我的上一篇文章中,我向您展示了如何模拟DDoS攻击以及如何缓解它。简单回顾一下,DDoS使用了大量的伪造请求,导致目标服务器消耗大量资源来处理这些无效请求,以至于无法正常响应正常的用户请求。在Linux服务器中,可以通过内核调优、DPDK、XDP等多种方式来提高服务器的抗攻击能力,降低DDoS对正常业务的影响。在应用中,可以使用各级缓存、WAF、CDN等来减轻DDoS对应用的影响。但是需要注意的是,如果DDoS流??量到达了Linux服务器,即使在应用层做了各种优化,网络服务延迟一般也会比平时大很多。所以在实际应用中,我们通常会使用带有专业流量清洗和网络防火墙设备的Linux服务器来缓解这个问题。除了DDoS导致的网络延迟增加,我想你一定见过很多其他原因导致的网络延迟,比如网络传输慢导致的延迟。由Linux内核堆栈中缓慢的数据包处理引起的延迟。应用数据处理慢等导致的延迟。那么遇到这些原因导致的延迟我们应该怎么办呢?如何定位网络延迟的根源?让我们在本文中讨论网络延迟。LinuxNetworkLatency说到网络延迟(NetworkLatency),人们通常认为是指网络数据传输所需要的时间。不过这里的“时间”指的是双向流量,即数据从源端发送到目的地,然后从目的地址返回响应的往返时间:RTT(Round-Trip时间)。除了网络延迟之外,另一个常用的指标是应用延迟(ApplicationLatency),它指的是一个应用从收到请求到返回响应所花费的时间。通常,应用程序延迟(也称为往返延迟)是网络数据传输时间加上数据处理时间的总和。通常人们使用ping命令来测试网络延迟,ping是基于ICMP协议的,它通过计算ICMP发送的响应报文和ICMP发送的请求报文之间的时间差来获得往返延迟时间。这个过程不需要特殊的认证,所以经常被很多网络攻击所利用,比如端口扫描工具nmap,分组工具hping3等。因此,为了避免这些问题,很多网络服务禁用了ICMP,这使得无法使用ping来测试网络服务的可用性和往返延迟。在这种情况下,您可以在TCP和UDP模式下使用traceroute或hping3来获取网络延迟。例如:#-c:3requests#-S:SetTCPSYN#-p:Setportto80$hping3-c3-S-p80google.comHPINGgoogle.com(eth0142.250.64.110):Sset,40headers+0databyteslen=46ip=142.250.64.110ttl=51id=47908sport=80flags=SAseq=0win=8192rtt=9.3mslen=46ip=142.250.64.110ttl=51id=6788sport=80flags=SAseq=1win=8192rtt=10.9mslen=46ip=142.250.64.110ttl=591SAidseport=5912win=8192rtt=11.9ms---baidu.comhpingstatistic---3packetstransmitted,3packetsreceived,0%packetlossround-tripmin/avg/max=9.3/10.9/11.9ms当然也可以使用traceroute:$traceroute--tcp-p80-ngoogle.comtraceroutetogoogle.com(142.250.190.110),30hopsmax,60bytepackets1***2240.1.236.340.198ms**3**243.254.11.50.189ms4*240.1.236.170.2140ms23417.2.0.182.716ms.150.234ms241.0.12.760.219ms...24142.250.190.11017.465ms108.170.244.118.532ms142.251.60.20718.595ms会在每三跳routetraceohroute包中发送,响应后输出往返时延已收到。如果没有响应或者响应超时(默认5s),会输出星号*。案例展示我们需要在这个演示中托管host1和host2两个主机:host1(192.168.0.30):托管两个Nginxweb应用程序(正常和延迟)host2(192.168.0.2):分析主机host1在host1上准备就绪,让我们运行并开始twocontainers,theofficialNginxandtheNginxwithadelayedversion:#Officialnginx$dockerrun--network=host--name=good-itdnginxfb4ed7cb9177d10e270f8320a7fb64717eac3451114c9fab3c50e02be2e88ba2#Latencyversionofnginxfexdnginx--work--name/nginx:latencyb99bd136dcfd907747d9c803fdc0255e578bad6d66f4e9c32b826d75b6812724Runthefollowingcommandtoverifythatboth容器正在服务流量:$curlhttp://127.0.0.1...

Thankyouforem>ngin/p>$curlhttp://127.0.0.1:8080...

感谢您使用nginx。

host2ready现在让我们用上面提到的hping3测试它们的延迟,看看有什么不同。在host2中执行以下命令分别测试案例机8080端口和80端口的延迟:80端口:$hping3-c3-S-p80192.168.0.30HPING192.168.0.30(eth0192.168.0.30):Sset,40headers+0databyteslen=44ip=192.168.0.30ttl=64DFid=0sport=80flags=SAseq=0win=29200rtt=7.8mslen=44ip=192.168.0.30ttl=64DFid=0sport=80flags=SAseq=1win=29200rtt=7.7ms9len41ip=1.0.30ttl=64DFid=0sport=80flags=SAseq=2win=29200rtt=7.6ms---192.168.0.30hpingstatistic---3packetstransmitted,3packetsreceived,0%packetlossround-tripmin/avg/max=7.6/7.7/7.8ms8080端口:#测试8080端口延时$hping3-c3-S-p8080192.168.0.30HPING192.168.0.30(eth0192.168.0.30):Sset,40headers+0databyteslen=44ip=192.168.0.30ttl=64DFid=0sport=8080flags=SAseq=0win=29200rtt=7.7mslen=44ip=192.168.0.30ttl=64DFid=0sport=8080flags=SAseq=1win=29200rtt=7.6mslen=44ip=192.168.0.30ttl=64DFid=0sport=8080flags=SAseq=2920rt3---192.168.0.30hpingstatistic---3packetstransmitted,3packetsreceived,0%packetlossround-tripmin/avg/max=7.3/7.6/7.7ms从此输出中,您可以看到两个端口的延迟大致相同,均为7ms。但这仅适用于单个请求。如果切换到并发请求怎么办?接下来,让我们用wrk(https://github.com/wg/wrk)试试看。80端口:$wrk--latency-c100-t2--timeout2http://192.168.0.30/Running10stest@http://192.168.0.30/2threadsand100connectionsThreadStatsAvgStdevMax+/-StdevLatency9.19ms12.32ms319.61ms97.80k2%Req0k0k0.808.25k85.50%LatencyDistribution50%7.78ms75%8.22ms90%9.14ms99%50.53ms123558requestsin10.01s,100.15MBreadRequests/sec:12340.91Transfer/sec:10.00MB8080Port:$wrk/timeout2http--c/192.168.0.30:8080/Running10stest@http://192.168.0.30:8080/2threadsand100connectionsThreadStatsAvgStdevMax+/-StdevLatency43.60ms6.41ms56.58ms97.06%Req/Sec1.15k120.291.92k88.50%LatencyDistribution50%44.02ms75%44.33ms90%47.62ms99%48.88ms22853requestsin10.01s,18.55MBreadRequests/sec:2283.31Transfer/sec:1.85MB从上面两个输出可以看出官方Nginx(监听80端口)的平均延迟是9.19ms,而案例Nginx(监听8080端口)用平均延迟为43.6毫秒。从延迟分布来看,Nginx官方可以在9ms内完成90%的请求;对于Nginx的情况,50%的请求都达到了44ms。那么这是怎么回事?让我们做一些分析:在host1上,让我们使用tcpdump捕获一些网络数据包:$tcpdump-nntcpport8080-wnginx.pcap现在,重新运行wrk命令$wrk--latencyonhost2-c100-t2--timeout2http://192.168.0.30:8080/当wrk命令结束后,再次切换回Terminal1(host1的终端),按Ctrl+C结束tcpdump命令。然后,使用Wireshark将抓取的nginx.pcap复制到本机(如果VM1(host1的虚拟机)已经有图形界面,可以跳过复制步骤),使用Wireshark打开。由于网络数据包比较多,我们可以先过滤一下。例如,选中一个数据包后,可以右键选择“Follow”->“TCPStream”,如下图所示:然后,关闭弹出对话框,返回Wireshark主窗口。这时候你会发现Wireshark已经自动为你设置了一个过滤表达式tcp.streameq24。如下图(图中省略了源IP和目的IP):从这里可以看到这个TCP连接从三次握手开始的每一次请求和响应。当然,这样可能不够直观,可以继续点击菜单栏中的Statistics->FlowGraph,选择“Limittodisplayfilter”,将Flowtype设置为“TCPFlows”:请注意左侧图中最右边是客户端,右边是Nginx服务器。从这个图中可以看出,前三次握手和第一次HTTP请求和响应都相当快,但是第二次HTTP请求就比较慢了,尤其是客户端收到服务器发来的第一个数据包之后。ACK响应(图中的蓝线)在40毫秒后发送。看到40ms这个值,是不是想到了什么?实际上,这是TCP延迟ACK的最小超时时间。这是TCPACK的一种优化机制,即不是每次请求都发送ACK,而是等待一段时间(比如40ms),看是否有“搭车”的数据包。如果这段时间还有其他数据包要发送,它们将与ACK一起发送。当然,如果不能等待其他包,超时后会单独发送ACK。由于案例中的client有40ms的延迟,我们有理由怀疑client启用了延迟确认机制。这里的client其实就是之前运行的wrk。根据TCP文档,只有在为TCP套接字专门设置了TCP_QUICKACK时才会启用快速确认模式(FastAcknowledgmentMode);otherwise,thedelayedacknowledgmentmechanismwillbeusedbydefault:TCP_QUICKACK(sinceLinux2.4.4)Enablequickackmodeifsetordisablequickackmodeifcleared.Inquickackmode,acksaresentimme‐diately,ratherthandelayedifneededinaccordancetonormalTCPoperation.Thisflagisnotperma‐nent,itonlyenablesaswitchtoorfromquickackmode.SubsequentoperationoftheTCPprotocolwillonceagainenter/leavequickackmodedependingoninternalprotocolprocessingandfactorssuchasdelayedacktimeoutsoccurringanddatatransfer.Thisoptionshouldnotbeusedincodeintendedtobeportable.让我们测试一下我们的质疑:$strace-fwrk--latency-c100-t2--timeout2http://192.168.0.30:8080/...setsockopt(52,SOL_TCP,TCP_NODELAY,[1],4)=0...可以看到wrk只设置TCP_NODELAY选项,但不设置TCP_QUICKACK。现在你可以看到延迟Nginx(caseNginx)响应有延迟的原因了。结论在本文中,我将向您展示如何分析增加的网络延迟。网络延迟是核心网络性能指标。由于网络传输、网络包处理等多种因素的影响,网络延迟是不可避免的。但是过多的网络延迟会直接影响用户体验。使用hping3、wrk等工具确认单个请求和并发请求的网络延迟是否正常。使用traceroute,确认路由正确,并查看路由上每个网关跃点的延迟。使用tcpdump和Wireshark确认正在发送和接收网络数据包。使用strace等观察应用程序对网络socket的调用是否正常。