作用
在实际有很多tcp连接的生产环境中,我们可能遇到大量CLOSE_WAIT状态的tcp连接导致的服务器资源被耗尽,导致的其他客户端的tcp连接不上的问题。
这种问题可能是客户端的tcp连接/重连相关代码的问题。
所以我们需要通过排查当前服务器的所有tcp的连接状态来排查问题。
统计当前服务器的所有tcp连接状态
netstat -an | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
结果:
LAST_ACK 4
LISTEN 22
SYN_RECV 4
CLOSE_WAIT 8
ESTABLISHED 1812
FIN_WAIT2 4
TIME_WAIT 5
CLOSING 4
单纯统计某个状态的
netstat -an |grep CLOSE_WAIT | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
CLOSE_WAIT为某个状态的对应的。
结果:
CLOSE_WAIT 19
如果发现了大量的CLOSE_WAIT,我们可以直接netstat -an列出所有的连接,然后查看是哪个tcp连接处于CLOSE_WAIT,通过判断其连接本地的端口和远程的IP信息来排查问题。
如果这时候看到大量的CLOSE_WAIT,我们查看tcp队列是否溢出
netstat -s | egrep "listen|LISTEN"
结果可能如下:
10043152 times the listen queue of a socket overflowed
10820426 SYNs to LISTEN sockets dropped
10043152 times 表示全连接队列溢出的次数,隔一阵刷新一下,如果发现这个数字还在涨,那说明有问题。
处理方法
手动强制清除CLOSE_WAIT
ss --tcp state CLOSE-WAIT --kill
参考:https://qa.1r1g.com/sf/ask/1113865931/
tcp状态说明
-
LAST_ACK
被动关闭端一段时间后,接收到文件结束符的应用程序将调用CLOSE关闭连接,这导致它的TCP也发送一个 FIN,等待对方的ACK,就进入了LAST-ACK。 -
LISTEN
服务端打开一个socket进行监听。 -
SYN_RECV
服务端应发出ACK确认客户端的SYN,同时自己向客户端发送一个SYN,之后状态置为SYN_RECV。 -
CLOSE_WAIT
被动关闭(passive close)端TCP接到FIN后,就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序),并进入CLOSE_WAIT。 -
ESTABLISHED
代表一个打开的连接,双方可以进行或已经在数据交互了。 -
FIN_WAIT1
主动关闭(active close)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态。 -
FIN_WAIT2
主动关闭端接到ACK后,就进入了FIN-WAIT-2。 -
TIME_WAIT
在主动关闭端接收到FIN后,TCP就发送ACK包,并进入TIME-WAIT状态。
TIME_WAIT状态的形成只发生在主动关闭连接的一方。
-
CLOSING
等待远程TCP对连接中断的确认。 -
SYN_SENT
客户端通过应用程序调用connect进行active open,于是客户端tcp发送一个SYN以请求建立一个连接,之后状态置为SYN_SENT。 -
CLOSED
被动关闭端在接受到ACK包后,就进入了closed的状态,连接结束。
netstat
参数说明
通过上面的统计指令,我们可以看到-an,这是一些参数。
-a
netstat默认是不显示LISTEN和LISTENING状态的,-a代表all,即显示所有,包括LISTEN和LISTENING状态。
-l
只显示LISTEN和LISTENING状态的信息。
-n
拒绝显示别名,能显示数字的全部转化成数字。
-t
仅显示tcp相关选项。
-u
仅显示udp相关选项。
-c
每隔一个固定时间,执行该netstat命令。
参考
https://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316661.html
参考
大量TIME_WAIT和CLOSE_WAIT分析
https://www.cnblogs.com/xinfang520/p/8961129.html
分享一次排查CLOSE_WAIT过多的经验
https://www.icode9.com/content-4-915193.html