浅谈CLOSE_WAIT

标签: Technical Linux TCP | 发表时间:2016-01-19 20:19 | 作者:老王
出处:http://huoding.com

TCP 有很多连接状态,每一个都够聊十块钱儿的,比如我们以前讨论过 TIME_WAITFIN_WAIT1,最近时不时听人提起 CLOSE_WAIT,感觉有必要梳理一下。

所谓 CLOSE_WAIT,借用某位大牛的话来说应该倒过来叫做 WAIT_CLOSE,也就是说「等待关闭」,如果你还不理解其含义,可以看看 TCP 关闭连接时的图例:

TCP Close

TCP Close

不要被图中的 client 和 server 所迷惑,你只要记住:主动关闭的一方发出 FIN 包,被动关闭的一方响应 ACK 包,此时,被动关闭的一方就进入了 CLOSE_WAIT 状态。如果一切正常,稍后被动关闭的一方也会发出 FIN 包,然后迁移到 LAST_ACK 状态。

通常,CLOSE_WAIT 状态在服务器停留时间很短,如果你发现大量的 CLOSE_WAIT 状态,那么就意味着被动关闭的一方没有及时发出 FIN 包,一般有如下几种可能:

  • 程序问题:代码层面遗漏或者死循环之类的,没有 close 相应的 socket 连接。
  • 响应太慢:对方已经 timeout 了,本方还忙于耗时逻辑,导致 close 被延后。
  • BACKLOG 太大:队列堆积严重,导致多余的请求来不及消费就被关闭了。

如果遭遇了 CLOSE_WAIT 故障,那么需要立刻通过「netstat」或者「ss」命令来判断 CLOSE_WAIT 连接是哪些进程引起的,如果是我们自己写的一些程序,比如用 HttpClient 自定义的蜘蛛,那么八九不离十是忘记了 close 相应的 socket,如果是一些使用广泛的程序,比如 Tomcat 之类的,那么不太可能是它们自身的 BUG,更可能是响应速度太慢或者 BACKLOG 设置过大导致的故障。

此外还有一点需要说明:按照前面图例所示,当被动关闭的一方处于 CLOSE_WAIT 状态时,主动关闭的一方处于 FIN_WAIT2 状态。 那么为什么我们总听说 CLOSE_WAIT 状态过多的故障,但是却相对少听说 FIN_WAIT2 状态过多的故障呢?这是因为 Linux 有一个「tcp_fin_timeout」设置,控制了 FIN_WAIT2 的最大生命周期。坏消息是 CLOSE_WAIT 没有类似的设置,如果不重启进程,那么 CLOSE_WAIT 状态很可能会永远持续下去;好消息是如果连接开启了 keepalive 机制,那么可以通过对应的设置来清理无效连接,不过 keepalive 是治标不治本的方法,还是应该对照前面的解释找到问题的症结才对。

本来想多写点的,但是着急下班回家,就写到这吧,结尾推荐两个案例:

写得都比我好,建议大家仔细阅读。

 

相关 [close wait] 推荐:

单条日志过长引发的 CLOSE-WAIT 问题

- - DockOne.io
部分租户称他们的某个业务部署在 Kubernetes 容器平台后经常会重启,部分租户称另一个业务在运行一段时间时会产生大量的 CLOSE-WAIT,还有的就是业务跑着就会 hang 住. 其实这三个问题,经过我们排查后,都是同一个问题引起,这也是我今天要分享的主题内容. 大家都知道,重启我们不好查,因为原因太多了,比如:容器分配的内存不够会重启,运行中程序内存泄漏到将内存耗尽会重启;在 Kubernetes 中配置了容器运行时健康检查时,如果条件未达到会重启等等;总之不好排查.

wait、sleep、yield区别

- - CSDN博客推荐文章
1、属于Object的本地方法. 2、暂停当前线程,并释放锁. 3、调用notify()或notifyAll()方法唤醒线程. 1、Thread类的静态方法. 2、当前线程休眠,但不释放锁. 3、其他线程可以继续执行,无论该线程优先级高与否. 4、休眠一段时间后,自动执行. 1、Thread类的静态方法.

Java多线程之wait()和notify()

- - CSDN博客推荐文章
直接看测试代码吧,细节之处,详见注释.  * Java多线程之wait()和notify()的妙用 .  * @see 问题:同时启动两个线程和同时启动四个线程,控制台打印结果是不同的 .  * @see      同时启动两个线程时,控制台会很规律的输出1010101010101010 .  * @see      同时启动四个线程时,控制台起初会规律的输出10101010,一旦某一刻输出一个负数,那么后面的输出就会"一错再错" .

java多线程设计wait/notify机制

- - CSDN博客推荐文章
  当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait() , 放弃对象锁..   之后在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:.   # 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {…} 代码段内.

Java多线程之wait和notify

- - ITeye博客
最近在看Java特种兵,看到多线程部分,对wait和notify不是很理解,于是写了代码来帮助理解.              wait方法通过参数可以指定等待的时长. 如果没有指定参数,默认一直等待直到被通知. notify方法是通知某个正在等待这个对象的控制权的线程可以继续运行. 调用wait方法时候,必须加上synchronized同步块,不然会抛出java.lang.IllegalMonitorStateException异常.

Java Sleep() 与 Wait()的机制原理与区别

- - CSDN博客推荐文章
Java中的多线程是一种抢占式的机制而不是分时机制. 线程主要有以下几种状态:可运行,运行,阻塞,死亡. 抢占式机制指的是有多个线程处于可运行状态,但是只有一个线程在运行.        当有多个线程访问共享数据的时候,就需要对线程进行同步.        Thread类的方法:sleep(),yield()等.

[转载]java之yield(),sleep(),wait()区别详解

- - 移动开发 - ITeye博客
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁. 也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据. 例如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行;但是高优先级的线程sleep(500)后,低优先级就有机会执行了.

最简实例说明wait、notify、notifyAll的使用方法

- - Java - 编程语言 - ITeye博客
wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态. 这三个方法最终调用的都是jvm级的native方法. 随着jvm运行平台的不同可能有些许差异. •如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态.