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

关于Titm_Wait优化,你一定知道...

时间:2023-03-22 13:07:13 科技观察

大家好,今天要讲的话题是关于TCP的TIME-WAIT状态TIME-WAIT是服务器优化中必须要讲的话题,以及我们常见的问题是TIME-WAIT过多怎么处理?常见的解决方案是:1、快速回收2、链接复用。这里有个误区就是TIME-WAIT应该优化到什么程度。有的童鞋甚至看到TIME-WAIT都觉得需要优化一下。今天我只想谈谈这个话题。要理解它,就要从TIME-WAIT是TCP连接的一种状态的原理说起。之前写过一篇文章介绍TCP的11种连接状态。有兴趣的可以再看看这张图,它展示了所有状态的转换过程。它分为三个部分。上半部分是建立连接的过程。下半部分分为主动关闭和被动关闭的过程。可以看到TIME_WAIT只是主动关闭。其实TIME_WAIT是TCP为了解决复杂的网络问题而提出的一种方案。它解决了什么问题?看下面两个场景,挥手四次。A发送FIN,B回复ACK,B再次发送FIN。A响应ACK关闭连接。而如果A的回应的ACK包丢失,B会认为A没有收到自己的关闭请求,然后重试发送一个FIN包给A。如果没有TIME_WAIT状态,A就不再保存这个的信息连接,收到一个不存在的连接的包,A会响应RST包,导致B响应异常。此时TIME_WAIT是为了保证全双工TCP连接的正常终止。我们也知道TCP下的IP层协议不能保证数据包传输的顺序。如果双方挥手后,回收了一个网络四元组(src/dstip/port),此时网络中有一个迟到的数据包还没有被B接收到,A应用立即使用同一个quadruple建立新的连接后,这个迟到的数据包到达了B,那么这个数据包会让B认为是刚刚A发送过来的。此时TIME_WAIT的存在就是为了保证数据包在网络中丢失正常过期。第一种场景TIME_WAIT是为了保证被动关闭方收到ACK,连接正常关闭,下次连接不会因为被动关闭方重传FIN而受到影响。第二种场景,TIME_WAIT预留2个MSL,保证数据不会丢失注:MSL(MaximumSegmentLifetime)最大段生存期,表示一个TCP段在Internet系统中可以存在的最长时间,由TCP实现,超过这个生命周期的段将被丢弃,RFC1122推荐2分钟,但在不同的Unix实现中,这个值是不确定的。由于以上两种情况,TCP引入了TIME_WAIT状态来解决。可见TIME_WAIT并不是完全不存在,它是合理的或者说是优化消除TIME_WAIT的一个目标,具体如何优化TIME_WAIT,什么样的状态才是合理的状态?让我们看看两种常用的优化方法。再来说说不推荐的:快速恢复。从上面可以看出,TIME_WAIT的持续时间是2MSL。根据RFC推荐,2分钟为4分钟。对于高并发的服务器来说,local_port本身是固定的。如果TIME_WAIT在4分钟后被回收,端口很快就会被耗尽。虽然在CentOS系统中,MSL可以通过修改参数tcp_fin_timeout来设置MSL时间。默认值为30秒。在这种情况下,四元组(local_ip、local_port、remote_ip、remote_port)将被冻结60s。系统默认可以分配大约30,000个端口。可以查看文件/proc/sys/net/ipv4/ip_local_port_range,当同一个客户端发起请求时,并发只能达到500QPS左右。因此,提出了一种快速回收的方法,即当TCP连接状态为TIME_WAIT状态时,立即回收该连接。等待2MSL为新连接快速回收资源以及快速回收的缺点相信大家都知道快速回收导致SYN得不到ACK的问题,具体如下:TCP有一个行为可以缓存最新的数据每次连接的后续请求中的时间戳如果小于缓存的时间戳,则认为无效,相应的数据包将被丢弃。Linux是否开启这个行为取决于tcp_timestamps和tcp_tw_recycle,因为tcp_timestamps是默认开启的,所以当tcp_tw_recycle开启时,这个行为实际上被激活了。在nat环境下,时间戳会被混淆,后面的数据包会被丢弃。具体表现通常是client明明发送了SYN,而server却没有回应ACK。由于NAT设备将数据包的源IP地址更改为一个地址(或少量IP地址),但基本不修改TCP包的时间戳,所以会造成时间戳混乱。建议:如果前端部署三/四层NAT设备,尽量关闭快速回收,避免NAT后真机时间戳混乱导致SYN拒绝问题。另一种优化方法是建议的方法:复用可以通过上面的分析确定,不上去就是问题。因为四元数被冻结了2MSL,没有新的资源可用,在冻结的时间内不能使用四元数,所以提出了复用的方法,但是复用是有前提的,需要tcp_timestamps,同时看代码内核的这一部分。复用的前提是在收到最后一个包后需要1秒以上,所以一般情况下,开启复用可以快速复用处于TIME_WAIT状态的socket链接,不会出现除了以上两种情况解决TIME_WAIT的方法,还有一个必须注意的参数,对于recycle这样的“副作用”,就是tw_buckets。可以通过cat/proc/sys/net/ipv4/tcp_max_tw_buckets查看该参数的值。这个值是TIME_WAIT可以达到的最大值。当TIME_WAIT的个数与tcp_max_tw_buckets相同时,就会处于tw_buckets的溢出状态。默认为4096,当reuse被放弃时,在高并发的服务器上,TIME_WAIT不会被快速回收,而是多次使用之前的链接,这种情况下,TIME_WAIT必然会保持一定量,所以tw_buckets很重要。如果local_port在3w左右,那么如果tw_buckets是默认的4096,TIME_WAIT很快就会达到瓶颈,不能再用了。增加,所以你应该保持tw_buckets至少在local_port之上。虽然长时间大量的TIME_WAIT会消耗一定的内存资源,但是对于当前的服务器来说,TIME_WAIT占用的内存是可以承受的。它已被弃用,因此它不是TIME_WAIT优化的最佳解决方案。最好的方法是通过重用来重用。复用的前提是开启tcp_timestamps,并注意tw_buckets溢出,适当增加tw_buckets以应对并发本文转载自微信公众号“运维研究社”,可通过关注下方二维码转载本文,请联系运维研究院公众号。