`
shixiaomu
  • 浏览: 375836 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

tcp通道关闭时,发生了什么? time_wait close_wait

 
阅读更多
tcp通道关闭时,发生了什么?

   前段时间,同事发现一个采用Thrift TheadPoolServer作为TCP的服务出现了大量的CLOSE_WAIT状态的socket。当第一次遇到这种问题的时候,你可能会有如下的问题:

    什么是CLOSE_WAIT? 为什么会发生?
    还有其他类似状态我不知道的么?

其实,你真正想问的是:

    当tcp通道关闭时,发生了什么事情?
    我该怎么办?

TCP通道是一个连接,连接的两端都可以向通道里写数据或者从通道里读数据,连接的两端都可以发起关闭操作。整个TCP通道的关闭流程如下:

A(socketfd:10) <——–TCP Connction ———->B(socketfd:20)

    关闭A,则A向B发送FIN;
    B接受到FIN后,返回一个ACK,表明收到了关闭通知, 当B返回ACK后,状态就转变为CLOSE_WAIT(!)了,它在等待什么呢?等待程序显式(手动)的关闭socket B。如果打开B的程序在发出ACK后,没有做任何处理,那么它就一直处于CLOSE_WAIT中了。
    如果程序显式的关闭了B,那么B会向A发送一个FIN,然后B就处于LAST_ACK状态了;
    A在接受到B的FIN后,发出最后一个ACK,此时A就处于知名的TIME_WAIT状态了。TIME_WAIT时间一般会比较长。

如何避免CLOSE_WAIT? 太多的CLOSE_WAIT通常意味着你程序中存在着严重的问题:没有正确处理socket的关闭事件,去查看代码吧。

如何避免TIME_WAIT? 通常,这是一个不应该问的问题,应该先问自己,TIME_WAIT真的给你带来麻烦了么? TIME_WAIT是可靠性的保证机制,没有必要去避免它。但或许,你可以尝试一下使用RFC1323。如果某一端实在是有太多的TIME_WAIT而造成问题,我建议的策略是:

    尽量避免TIME_WAIT过多的一端主动关闭socket
    使用SocketPool,避免频繁创建/关闭socket


提到Thrift ThreadPoolServer有时候会出现较多的close wait状态,有朋友问我这是不是thrift的bug?写过Server比较多的同志们应该能意识到这个问题的原因,不值得说,可是我今天实在是太郁闷无聊了,我就写写我的想法吧。

我觉得这当然不能算是Thrift的Bug,如果出现了这样的问题,其实是因为错误的选择了Server的类型,错误的实现了Client,过于保守的Server Max Connection配置等等原因。

对于ThreadPoolServer而言,每一个客户端连接,Server端都需要提供一个固定的线程来维护,在空闲时,线程堵塞在read()操作,等待客户端数据的到来。Thrift ThreadPoolServer中使用的默认线程池是定长线程池,意味着Server端能提供的线程池数是有限的。当线程用完时,新的连接将不能得到Server殷勤的服务,它不会在乎你的生死,你必须等待。

举个例子:

    我有一个用Thrift ThreadPoolServer(使用SimpleThreadPool)实现的Server,最大支持100个连接,现在有100个客户端连接到我的Server。实现客户端的程序员都很在乎TCP连接建立的开销,因此,他们都维护了一个长连接。这个时候,如果有第101个客户端连接到Server了,会发生什么情况呢?

    Server会接受这个连接,连接成功建立;
    Server没有合适的线程来处理这个连接,于是将这个连接放到暂存列表;
    如果这个时候有线程空闲了,则一切顺利,这个线程将接管这个连接;
    但遗憾的是,我们没有空闲线程,所以这个连接一直处于空闲状态,直到客户端程序timeout(如果设置了timeout的话);
    连接timeout,意味着暂存列表里的连接已经失效了,此时对应的socket处于CLOSE_WAIT中(出现了本文开头的情况),遗憾的是,我们依然没有空闲的线程来处理这个连接,所以它一直处于CLOSE_WAIT中。
    终于,某一个时刻,有一个客户端关闭了连接,我们有了空闲线程,它去查看暂存列表。发现有一个socket fd,尝试去接管它,对这个fd执行read(),然后得到一个Connection Reset error,终于,我们可以优雅的关闭它了(CLOSE_WAIT结束)。
    以上就是全部的故事。

那么,要怎么办?

    1.如果连接数太多,为什么不用NonBlockingServer呢?Thrift有基于libevent的实现,虽然它的ThreadPool限制了NonblockingServer的性能,但是,你可以方便的实现一个存/取线程更高效的ThreadPool.
    2.你可以实现一个TimeoutCachedThreadPool来替代SimpleThreadPool.
    3.提高Max Connection的值.
分享到:
评论

相关推荐

    tcp连接出现close_wait状态?_tcp_close_

    tcp连接出现close_wait状态?

    TCP的状态兼谈Close_Wait和Time_Wait的状态

    详细描述TCP的各个状态,初学者可以快速理解掌握tcp状态图

    CLOSE_WAIT网络连接无法释放问题解决

    关于系统端口出现CLOSE_WAIT状态的解决方案,讲解明确清晰,值得参考

    TCP状态迁移,CLOSE_WAIT & FIN_WAIT2 的问题解决

    对于服务器挂起中的CLOSE_WAIT & FIN_WAIT2 解决方案。

    TCP_CloseWaitProblem

    这次我们了解到的是,只有在应用程序显式调用close或终止应用程序时,才可以接收等待CLOSE_WAIT的关闭。 因此,如果您在这种CLOSE_WAIT状态下无限期地等待,则会担心资源的浪费,唯一的终止方法是关闭调用或强制...

    c++《网络编程》服务器

    导致客户TCP发送一个FIN给服务器,服务器则以一个ACK响应,此时服务器处于CLOSE_WAIT状态,客户端处于FIN_WAIT_2状态。服务器接收到FIN,子进程中止。子进程中止内核关闭所有子进程打开的描述符导致服务器向客户端...

    获取TCP,UDP服务端口号.rar

    case MIB_TCP_STATE_TIME_WAIT: m_PortList.SetItemText(i,2,"TIME-WAIT"); break; case MIB_TCP_STATE_DELETE_TCB: m_PortList.SetItemText(i,2,"DELETE-TCB"); break; default: ...

    Tcp四次挥手.png

    1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。  2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个...

    TCP三次握手和四次挥手

    1. `CLOSE_WAIT`:四次挥手两次之后的状态,这个状态就是在等待代码当中调用`socket.close`方法,来进行后续的挥手过程!正常情况下一个服务器上不应该存在大量的`CLOST_WAIT`状态,如果大量存在大概率是代码的bug,...

    TCP-IP详解卷3:TCP事务协议

    10.6 tcp_close函数 89 10.7 tcp_msssend函数 90 10.8 tcp_mssrcvd函数 91 10.9 tcp_dooptions函数 96 10.10 tcp_reass函数 98 10.11 小结 99 第11章 T/TCP实现:TCP输入 101 11.1 概述 101 11.2 预处理 103 11.3 ...

    TCP-IP详解卷三

    10.6 tcp_close函数 89 10.7 tcp_msssend函数 90 10.8 tcp_mssrcvd函数 91 10.9 tcp_dooptions函数 96 10.10 tcp_reass函数 98 10.11 小结 99 第11章 T/TCP实现:TCP输入 101 11.1 概述 101 11.2 预处理 103 11.3 ...

    TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议——高清文字(china-pub经典系列)

    10.6 tcp_close函数 89 10.7 tcp_msssend函数 90 10.8 tcp_mssrcvd函数 91 10.9 tcp_dooptions函数 96 10.10 tcp_reass函数 98 10.11 小结 99 第11章 T/TCP实现:TCP输入 101 11.1 概述 101 11.2 预处理 103 11.3 ...

    TCP/IP详解 卷3:TCP事务协议、HTTP、NNTP和UNIX域协议

    10.6 tcp_close函数 10.7 tcp_msssend函数 10.8 tcp_mssrcvd函数 10.9 tcp_dooptions函数 10.10 tcp_reass函数 10.11 小结 第11章 T/TCP实现:TCP输入 11.1 概述 11.2 预处理 11.3 首部预测 11.4 被动打开的启动 ...

    TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议

    10.6 tcp_close函数 89 10.7 tcp_msssend函数 90 10.8 tcp_mssrcvd函数 91 10.9 tcp_dooptions函数 96 10.10 tcp_reass函数 98 10.11 小结 99 第11章 T/TCP实现:TCP输入 101 11.1 概述 101 11.2 预处理 103 11.3 ...

    TCP-IP详解卷3:TCP事务协议,HTTP,NNTP和UNIX域协议.rar

    10.6 tcp_close函数 89 10.7 tcp_msssend函数 90 10.8 tcp_mssrcvd函数 91 10.9 tcp_dooptions函数 96 10.10 tcp_reass函数 98 10.11 小结 99 第11章 T/TCP实现:TCP输入 101 11.1 概述 101 11.2 预处理 103 11.3 ...

    python基础超强总结

    Python Python深拷贝和浅拷贝的区别 Python的内存管理机制(垃圾回收+内存池) ⼀、引用计数 ⼆、垃圾回收 三、内存池机制 ...S 为什么TIME_WAIT状态需要经过OMSL才能返回到CLOSE状态? TCP VS UDP ⼀、TCP/IP网络

    TCP-IP详解卷3.rar

    10.6 tcp_close函数 89 10.7 tcp_msssend函数 90 10.8 tcp_mssrcvd函数 91 10.9 tcp_dooptions函数 96 10.10 tcp_reass函数 98 10.11 小结 99 第11章 T/TCP实现:TCP输入 101 11.1 概述 101 11.2 预处理 103 11.3 ...

    TCP/IP详解part_2

    18.5 TCP的半关闭 180 18.6 TCP的状态变迁图 182 18.6.1 2MSL等待状态 183 18.6.2 平静时间的概念 186 18.6.3 FIN_WAIT_2状态 186 18.7 复位报文段 186 18.7.1 到不存在的端口的连接请求 187 18.7.2 异常终止一个...

    TCP_IP详解卷1

    18.5 TCP的半关闭 180 18.6 TCP的状态变迁图 182 18.6.1 2MSL等待状态 183 18.6.2 平静时间的概念 186 18.6.3 FIN_WAIT_2状态 186 18.7 复位报文段 186 18.7.1 到不存在的端口的连接请求 187 18.7.2 异常终止一个...

Global site tag (gtag.js) - Google Analytics