• TCP连接问题之CLOSE_WAIT和TIME_WAIT过多


    参考博文

    https://dengqsintyt.iteye.com/blog/2086485

    Timeout waiting for connection异常排查:https://blog.csdn.net/shootyou/article/details/6615051

    再谈应用环境下的TIME_WAIT和CLOSE_WAIT:https://blog.csdn.net/shootyou/article/details/6622226

    Nginx做前端Proxy时TIME_WAIT过多的问题:https://blog.csdn.net/shootyou/article/details/44199849

    一、TIME_WAIT(通过优化系统内核参数可容易解决) 

    TIME_WAIT是主动关闭连接的一方保持的状态,对于服务器来说它本身就是“客户端”,在完成一个爬取任务之后,它就会发起主动关闭连接,从而进入TIME_WAIT的状态,然后在保持这个状态2MSL(max segment lifetime)时间之后,彻底关闭回收资源。为什么要这么做?明明就已经主动关闭连接了为啥还要保持资源一段时间呢?这个是TCP/IP的设计者规定的,主要出于以下两个方面的考虑:

            1.防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)

            2.可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。

            解决方案很简单,通过修改/etc/sysctl.conf文件,服务器能够快速回收和重用那些TIME_WAIT的资源

    Shell代码  收藏代码
    1. #表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭    
    2. net.ipv4.tcp_syncookies = 1    
    3. #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭    
    4. net.ipv4.tcp_tw_reuse = 1    
    5. #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭    
    6. net.ipv4.tcp_tw_recycle = 1  
    7. #表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间    
    8. net.ipv4.tcp_fin_timeout=30  

    二、CLOSE_WAIT(需要从程序本身出发)

           TCP状态转移要点

           TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源.

            客户端TCP状态迁移:        

    Java代码  收藏代码
    1. CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED  
         
             服务器TCP状态迁移:      
    Java代码  收藏代码
    1. CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED  

           当客户端开始连接时,服务器还处于LISTENING,客户端发一个SYN包后,他就处于SYN_SENT状态,服务器就处于SYS收到状态,然后互相确认进入连接状态ESTABLISHED。

           TIME_WAIT状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的。

            但是CLOSE_WAIT就不一样了,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。个人觉得这种情况,通过服务器内核参数也没办法解决,服务器对于程序抢占的资源没有主动回收的权利,除非终止程序运行。

           什么情况下,连接处于CLOSE_WAIT状态呢?

           答案一:在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态。但是在一些特殊情况下,就会出现连接长时间处于CLOSE_WAIT状态的情况。

           答案二:出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno,如果不是AGAIN,就断开连接。

  • 相关阅读:
    log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
    警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:fhcq-oa' did not find a matching property.
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    Maven 仓库之阿里云镜像配置
    HashMap 在 Java1.7 与 1.8 中的区别
    MySQL 相关知识细节及解析
    JS 如何准确获取当前页面URL网址信息
    i++ 和 ++i
    常见浏览器兼容性问题与解决方案(面试题目)
    面试题目简单整理-完善中
  • 原文地址:https://www.cnblogs.com/heroinss/p/10642670.html
Copyright © 2020-2023  润新知