赞
踩
TCP连接状态分析:
CLOSED 表示socket连接没被使用。 LISTENING 表示正在监听进入的连接。 SYN_SENT 表示正在试着建立连接。SYN_RECEIVED 进行连接初始同步。 ESTABLISHED 表示连接已被建立。 CLOSE_WAIT表示远程计算器关闭连接,正在等待socket连接的关闭。 FIN_WAIT_1 表示socket连接关闭,正在关闭连接。 CLOSING先关闭本地socket连接,然后关闭远程socket连接,最后等待确认信息。 LAST_ACK 远程计算器关闭后,等待确认信号。 FIN_WAIT_2 socket连接关闭后,等待来自远程计算器的关闭信号。 TIME_WAIT 连接关闭后,等待远程计算器关闭重发。
time_wait状态是一般有客户端的状态。而且会占用端口。有时产生在服务器端,因为服务器主动断开连接或者发生异常。
查询Windows下Close_Wait的ip和端口方法:
netstat -n -p tcp
1 起因
线上服务器nginx日志运行一段时间后,会报如下错误:
1024 worker_connections are not enough
一般做法是修改worker_connections。
但实际上:该服务是用于时间比较短的连接里,并且一天最多才4000个请求。不可能会耗尽worker_connections。
除非每次连接都没有释放对应的连接。
‘
shell>netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
CLOSE_WAIT 802
ESTABLISHED 106
shell>lsof -n | grep “nginx对应的一个进程id”
MvLogServ 31125 mv 111u IPv4 76653578 0t0 TCP 10.1.138.60:8996->10.1.138.60:51977 (CLOSE_WAIT)
MvLogServ 31125 mv 112u IPv4 76659698 0t0 TCP 10.1.138.60:8996->10.1.138.60:52015 (CLOSE_WAIT)
MvLogServ 31125 mv 113u IPv4 76662836 0t0 TCP 10.1.138.60:8996->10.1.138.60:52042 (CLOSE_WAIT)
MvLogServ 31125 mv 114u IPv4 76663435 0t0 TCP 10.1.138.60:8996->10.1.138.60:52051 (CLOSE_WAIT)
MvLogServ 31125 mv 115u IPv4 76682134 0t0 TCP 10.1.138.60:8996->10.1.138.60:52136 (CLOSE_WAIT)
MvLogServ 31125 mv 116u IPv4 76685095 0t0 TCP 10.1.138.60:8996->10.1.138.60:52159 (CLOSE_WAIT)
……………….
TIME_WAIT:表示主动关闭,通过优化系统内核参数可容易解决。
CLOSE_WAIT:表示被动关闭,需要从程序本身出发。
ESTABLISHED:表示正在通信
则可知:nginx:CLOSE_WAIT过多的状态
2 解决
2.1 TIME_WAIT 通过优化系统内核参数可容易解决
TIME_WAIT大量产生很多通常都发生在实际应用环境中。
TIME_WAIT产生的原因:在通讯过程中A主动关闭造成的,
在A发送了最后一个FIN包后,系统会等待 Double时间
的MSL(Max Segment Lifetime)【注:按不同的操作系统有不同时间】用于等待接受B发送过来的FIN_ACK和FIN,
这段时间A的对应的socket的fd是不能够重新利用的,
这样在大量的短连接服务中,会出现TIME_WAIT过多的现象。
解决方案:
调整TIME_WAIT超时时间
vi /etc/sysctl.conf
#表示开启SYN Cookies。
#当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_syncookies = 1
#表示开启重用。
#允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_tw_recycle = 1
#表示如果套接字由本端要求关闭。
#这个参数决定了它保持在FIN-WAIT-2状态的时间
#生效,如下命令
/sbin/sysctl -p
注:
已经主动关闭连接了为啥还要保持资源一段时间呢?
这个是TCP/IP的设计者规定的,主要出于以下两个方面的考虑:
防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)
即:允许老的重复分节在网络中消逝。
可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。
另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。
即:可靠地实现TCP全双工连接的终止。(确保最后的ACK能让被关闭方接收)
2.2 CLOSE_WAIT 需要从程序本身出发
LOSE_WAIT产生的原因是客户端B主动关闭,
服务器A收到FIN包,应用层却没有做出关闭操作引起的。
CLOSE_WAIT在Nginx上面的产生原因还是因为Nagle’s算法加Nginx本身EPOLL的ET触发模式导致。
ET出发模式在数据就绪的时候会触发一次回调操作,Nagle’s算法会累积TCP包,如果最后的数据包和
FIN包被Nagle’s算法合并,会导致EPOLL的ET模式只触发一次。
然而在应用层的SOCKET是读取返回0才代表链接关闭,
而读取这次合并的数据包时是不返回0的,
然后SOCKET以后都不会触发事件,
所以导致应用层没有关闭SOCKET,
从而产生大量的CLOSE_WAIT状态链接。
关闭TCP_NODELAY,在Nginx配置中加上
tcp_nodelay on;
3 总结
TIME_WAIT状态可以通过优化服务器参数得到解决。
因为发生TIME_WAIT的情况是服务器自身可控的,
要么就是对方连接的异常,要么就是自己没有迅速回收资源,
总之不是由于自己程序错误导致的。
CLOSE_WAIT需要通过程序本身。
如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。
即在对方连接关闭之后,程序里没有检测到,或者程序没有关闭连接,于是这个资源就一直被程序占着。
服务器对于程序抢占的资源没有主动回收的功能。只能修改程序本身。
代码需要判断socket,一旦读到0,断开连接,read返回负,
检查一下errno,如果不是AGAIN,就断开连接。
参考来源:
【1】http://www.cnblogs.com/Bozh/p/3752476.html
作者联系方式:Email:zhangbolinux@sina.com QQ:513364476
【2】http://itindex.net/detail/50213-%E6%9C%8D%E5%8A%A1%E5%99%A8-time_wait-close_wait
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。