CLOSE_WAIT你该知道的事
服务器怎么“挂”了
第一反应 (请注意,这里开始是大佬的排错思路)
从开始打开电脑到电脑点亮的时间里我已经想好了一个初步的排错检查思路, 既然是拿不到数据,那有哪些可能呢?
-
是不是特例还是所有情况下的数据都获取不到?
-
是不是网络断了(比如某厂的光缆又断了?)
-
是不是服务停了 (Sig 11?OOM?或者core dump)
-
是不是应用服务器都CPU 100%了?
-
看看监控系统有没有报警? (当然得有对吧)
-
看看DB是不是被人删了?(听过某盟的事件后,这总也是一种可能行对吧)
好,因为我们有云监控,看了下
-
SLB的心跳还活着,排除网络问题
-
所有服务器的CPU/Memory/IO都还正常没有峰值
-
关键进程还在
-
DB也还健在
开始检查
既然初步排除上述的问题,那下一步基本就是SSH到服务器上去看情况了。 自然从网络开始,这里要想说给很多在做或者即将做在线生产环境支持的小伙伴说的第一句话: “先听听操作系统的声音,让操作系统来告诉你问题在哪”。 不论是windows和Linux都提供了一堆小工具小命令,在过度依赖安装第三方工具前请先看看是否操作系统自带的工具已经不够支撑你了。
好,第一个检查就是本机的网络连接
netstat --atunlp
结果
又出现一堆CLOSE_WAIT!!!
什么是CLOSE_WAIT
TCP 有很多连接状态,比如 TIME_WAIT 和 FIN_WAIT1,最近时不时听人提起 CLOSE_WAIT,而且CLOSE_WAIT的出现往往是程序出了BUG,所以根据这一状态来定位问题很有用。先来看看TCP的状态转换图。
从这里可以看出CLOSE_WAIT是TCP状态中不可分割的一部分。
先谈谈CLOSE_WAIT的产生
注意:在关闭连接四次握手的过程中一般部分service端和client端,更为贴切的应该是主动端和被动段的叫法,因为service端和client端都可以主动关闭连接。
首先CLOSE_WAIT是TCP状态的一部分,它产生于被动段接收到了FIN包并发送了ACK包,进入CLOSE_WAIT 状态,如果一切正常,稍后被动关闭的一方也会发出 FIN 包,然后迁移到 LAST_ACK 状态。(通常,CLOSE_WAIT 状态在服务器停留时间很短)
CLOSE_WAIT出现的可能原因
程序问题
如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 也永远执行不到。
响应太慢或者超时设置过小
如果连接双方不和谐,一方不耐烦直接 timeout,另一方却还在忙于耗时逻辑,就会导致 close 被延后。响应太慢是首要问题,不过换个角度看,也可能是 timeout 设置过小。
backlog 太大
backlog介绍
服务器端TCP内核模块维护有2个队列,我们称之为A,B吧。A为未完成三次握手队列,B为完成三次握手队列。
客户端向服务器端connect的时候,挥发送带有SYN标志的包(第一次握手),服务器收到客户端发来的SYN时,向客户端发送SYN ACK确认(第二次握手),此时TCP内核模块把客户端连接加入到A队列中,然后服务器收到客户端发来的ACK时(第三次握手),TCP内核模块把客户端连接从A队列移到B队列,连接完成,应用程序的accept会返回。
也就是说accept从B队列中取出完成三次握手的连接。A队列和B队列的长度之和是backlog。当A,B队列的长度之和大于backlog时,新连接将会被TCP内核拒绝。
所以,如果backlog过小,可能会出现accept速度跟不上,A、B队列满了,导致新的客户端无法连接。
要注意的是:backlog对程序支持的连接数并无影响,backlog影响的只是还没有被accept取出的连接。
此处的 backlog 不是 syn backlog,而是 accept 的 backlog,如果 backlog 太大的话,设想突然遭遇大访问量的话,即便响应速度不慢,也可能出现来不及消费的情况,导致多余的请求还在队列里就被对方关闭了。
特此说明
此外还有一点需要说明:按照前面图例所示,当被动关闭的一方处于 CLOSE_WAIT 状态时,主动关闭的一方处于 FIN_WAIT2 状态。 那么为什么我们总听说 CLOSE_WAIT 状态过多的故障,但是却相对少听说 FIN_WAIT2 状态过多的故障呢?这是因为 Linux 有一个「tcp_fin_timeout」设置,控制了 FIN_WAIT2 的最大生命周期。坏消息是 CLOSE_WAIT 没有类似的设置,如果不重启进程,那么 CLOSE_WAIT 状态很可能会永远持续下去;好消息是如果 socket 开启了 keepalive 机制,那么可以通过相应的设置来清理无效连接,不过 keepalive 是治标不治本的方法,还是应该找到问题的症结才对。
文章参考
引入了大佬写文章的小故事的开头,来引入文章主题
https://mp.weixin.qq.com/s?__biz=MzI4MjA4ODU0Ng==&mid=402163560&idx=1&sn=5269044286ce1d142cca1b5fed3efab1&3rd=MzA3MDU4NTYzMw==&scene=6#rd