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

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

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

其实,你真正想问的是:

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

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

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

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

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

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

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

8 Comments »

  1. IUSR Said,

    December 20, 2010 @ 6:00 pm

    这个真是超常见。我们上次也碰见了,这种一般还伴随着不及时释放FD。

  2. sammychen Said,

    December 20, 2010 @ 6:09 pm

    恩,linux下,不及时关闭socket,同时就是没有及时释放fd啊。

  3. thrift, close wait – Writing Future Said,

    December 20, 2010 @ 10:04 pm

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

  4. IUSR Said,

    December 22, 2010 @ 12:09 am

    最近一个小朋友和OPS的一个很挑剔的人折腾这事儿来着。其实我觉得server有些过载了,某个时间段内出现这种情况没法很好地避免,负载下来以后能慢慢恢复的话还算说的过去(是这理不?牛人指点一下!)。可惜我司强大的scale工具得出的结论不支持我这说法,人家说离过载还早着哪,都怪程序没写好(scale工具模拟的应用数据简直太可爱了,要是服务器整天处理那种数据真是可以把我们都裁掉了)。

  5. sammychen Said,

    December 22, 2010 @ 1:27 pm

    CLOSE_WAIT吗?
    是负载高导致线程来不及处理关闭事件么?

  6. IUSR Said,

    December 22, 2010 @ 2:45 pm

    y,nio的一个服务线程知道要disconnect了,但是没有空闲worker线程来管,就这么放着,等空闲了,可能队列里还有很久以前留下的read任务,一读也就出错了,跟你后一篇里一样一样的。
    还有一个是没有finally然后碰见个unexpected异常直接飞掉了,serversocket就那么挂在那里…

  7. sammychen Said,

    December 23, 2010 @ 2:05 pm

    没有finally碰见异常直接飞掉了,这个算bug吧,嘿嘿。

  8. IUSR Said,

    December 23, 2010 @ 9:22 pm

    y,对最终海量的fd也有很大的贡献。
    哎,等try-with-resources吧,太容易忘记擦PG了。

Leave a Comment