服务器出现大量tcp TIME_WAIT 状态处理

 : jank    :   : 170    : 2019-07-29 15:29  linux

一、事故起源:

       1.公司有个golang http服务,通过nginx  做代理,当用户访问巨大的时候,服务端出现了大量的TIME_WAIT 。

       2.通过netstat 查看: 

   # netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"	",state[key]}'

二、造成TIME_WAIT 状态的原因:

       首先我们应该要弄清楚tcp关闭连接的四次握手原理:

       image.png

        如上图所示: 

           1.Client向Server发送FIN包,表示Client主动要关闭连接,然后进入FIN_WAIT_1状态,等待Server返回ACK包。此后Client不能再向Server发送数据,但能读取数据。

           2.Server收到FIN包后向Client发送ACK包,然后进入CLOSE_WAIT状态,此后Server不能再读取数据,但可以继续向Client发送数据。

           3.Client收到Server返回的ACK包后进入FIN_WAIT_2状态,等待Server发送FIN包。
           4.Server完成数据的发送后,将FIN包发送给Client,然后进入LAST_ACK状态,等待Client返回ACK包,此后Server既不能读取数据,也不能发送数据。
           5.Client收到FIN包后向Server发送ACK包,然后进入TIME_WAIT状态,接着等待足够长的时间(2MSL)以确保Server接收到ACK包,最后回到CLOSED状态,释放网络资源。

           6.Server收到Client返回的ACK包后便回到CLOSED状态,释放网络资源。

三、处理方案:

      1.通过更改系统配置:

          调整TIME_WAIT超时时间 
          vi /etc/sysctl.conf 
          #表示开启重用。 允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭 
          net.ipv4.tcp_tw_reuse = 1 
          #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭 
          net.ipv4.tcp_tw_recycle = 1 
       #生效,如下命令 
         /sbin/sysctl -p

          如上通过更改系统配置重用,可能会带来一些潜在的故障:

           Linux是否启用这种行为取决于tcp_timestamps和tcp_tw_recycle,因为tcp_timestamps缺省就是开启的,所以当tcp_tw_recycle被开启后,实际上这种行为就被激活了,当客户端或服务端以NAT方式构建的时候就可能出现问题,下面以客户端NAT为例来说明:

           当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。如果发生了此类问题,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK.

           

           安全起见,通常要禁止tcp_tw_recycle。说到这里,大家可能会想到另一种解决方案:把tcp_timestamps设置为0,tcp_tw_recycle设置为1,这样不就可以鱼与熊掌兼得了么?可惜一旦关闭了tcp_timestamps,那么即便打开了tcp_tw_recycle,也没有效果。

           好在我们还有另一个内核参数tcp_max_tw_buckets(一般缺省是180000)可用:

      # sysctl net.ipv4.tcp_max_tw_buckets=100000

          通过设置它,系统会将多余的TIME_WAIT删除掉,此时系统日志里可能会显示:「TCP: time wait bucket table overflow」,不过除非不得已,否则不要轻易使用。

          以上这些方式,只做到了治标不治本,显得还是很牵强。

       2.通过nginx <--> 服务端 进行长连接:

           nginx 1.1 以后的版本upstream已经支持keep-alive, 官方文档:http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive

    upstream http_backend {
        server 127.0.0.1:8080;
        keepalive 16;  
    }

        通过这种方式,TIME_WAIT数明显减少。 


参考链接:

       https://blog.csdn.net/godleading/article/details/50849253

       https://blog.huoding.com/2012/01/19/142




   

备案编号:赣ICP备15011386号

联系方式:qq:1150662577    邮箱:1150662577@qq.com