在服务器的平常维护过程当中,会常常用到下面的命令:linux
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
它会显示例以下面的信息:服务器
TIME_WAIT 814
CLOSE_WAIT 1
FIN_WAIT1 1
ESTABLISHED 634
SYN_RECV 2
LAST_ACK 1网络
经常使用的三个状态是:ESTABLISHED 表示正在通讯,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。socket
- TCP协议规定,对于已经创建的链接,网络双方要进行四次握手才能成功断开链接,若是缺乏了其中某个步骤,将会使链接处于假死状态,链接自己占用的资源不会被释放。网络服务器程序要同时管理大量链接,因此颇有必要保证无用链接彻底断开,不然大量僵死的链接会浪费许多服务器资源。在众多TCP状态中,最值得注意的状态有两个:CLOSE_WAIT和TIME_WAIT。
TIME_WAITtcp
- TIME_WAIT 是主动关闭连接时造成的,等待2MSL时间,约4分钟。主要是防止最后一个ACK丢失。 因为TIME_WAIT 的时间会很是长,所以server端应尽可能减小主动关闭链接
CLOSE_WAITspa
- CLOSE_WAIT是被动关闭链接是造成的。根据TCP状态机,服务器端收到客户端发送的FIN,则按照TCP实现发送ACK,所以进入CLOSE_WAIT状态。但若是服务器端不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在不少CLOSE_WAIT状态的链接。此时,多是系统忙于处理读、写操做,而未将已收到FIN的链接,进行close。此时,recv/read已收到FIN的链接socket,会返回0。
为何须要 TIME_WAIT 状态?code
- 假设最终的ACK丢失,server将重发FIN,client必须维护TCP状态信息以即可以重发最终的ACK,不然会发送RST,结果server认为发生错误。TCP实现必须可靠地终止链接的两个方向(全双工关闭),client必须进入 TIME_WAIT 状态,由于client可能面 临重发最终ACK的情形。
为何 TIME_WAIT 状态须要保持 2MSL 这么长的时间?server
- 若是 TIME_WAIT 状态保持时间不足够长(好比小于2MSL),第一个链接就正常终止了。第二个拥有相同相关五元组的链接出现,而第一个链接的重复报文到达,干扰了第二个链接。TCP实现必须防止某个链接的重复报文在链接终止后出现,因此让TIME_WAIT状态保持时间足够长(2MSL),链接相应方向上的TCP报文要么彻底响应完毕,要么被 丢弃。创建第二个链接的时候,不会混淆。
TIME_WAIT 和CLOSE_WAIT状态socket过多
若是服务器出了异常,百分之八九十都是下面两种状况:资源
-
1.服务器保持了大量TIME_WAIT状态class
-
2.服务器保持了大量CLOSE_WAIT状态,简单来讲CLOSE_WAIT数目过大是因为被动关闭链接处理不当致使的。
-
由于linux分配给一个用户的文件句柄是有限的,而TIME_WAIT和CLOSE_WAIT两种状态若是一直被保持,那么意味着对应数目的通道就一直被占着,并且是“占着茅坑不使劲”,一旦达到句柄数上限,新的请求就没法被处理了,接着就是大量Too Many Open Files异常,Tomcat崩溃。
做者:InnocenceYWQ 连接:https://www.jianshu.com/p/f6a563f3526c 来源:简书 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。