TCP 连接状态图 ,TIME_WAIT,CLOSE_WAIT解决办法

10 篇文章 1 订阅
7 篇文章 0 订阅

TCP联机在各种状态之间变动的状况与顺序,其中TIME_WAIT联机已经是TCP联机在完全关闭联机状态(CLOSED)之前的一个状态(注:完全关闭联机是指网络完整断线的意思),而预设TIME_WAIT的逾时时间为MSL(Maximum Segment Lifetime)时间的两倍,在RFC 793规格定义的MSL为两分钟,也就是在预设的情况下,每一条联机从打算关闭联机状态(Closing)换到完整关闭联机状态(Closed)之间还会停留在TIME_WAIT状态约4分钟的时间,如果你4分钟以内使用者建立的联机数超过65536条联机的话,那么很这台服务器就再也无法连接了。(注:Windows预设的TIME_WAIT时间为4分钟,Linux下则会依据不同Distribution版本而有不同的预设值,但都可以调整其时间长短)
MSL为一个TCP Segment(某一块TCP网络封包)从来源送到目的之间可续存的时间(也就是一个网络封包在网路上传输时能存活的时间),由于RFC 793 TCP传输协定是在1981年定义的,当时的网络速度不像现在的网际网络那样发达,你可以想像你从浏览器输入网址等到第一个byte出现要等4分钟吗?在现在的网络环境下几乎不可能有这种事情发生,因此我们大可将TIME_WAIT状态的续存时间大幅调低,好让联机端口(Ports)能更快空出来给其他联机使用。
注意:如果当系统所有可用的联机端口(Ports)都用光的话,就会接收到以下错误讯息:

WSAENOBUFS (10055) error: "An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full."

因此在流量较大的网站或服务器,应该是要调整Windows预设的TIME_WAIT存留时间才对,如果要缩短Windows预设的TIME_WAIT状态的续存时间可以调整以下机码值,微软建议最低可设定续存时间为30秒,而且也提到设定30秒应该不会出问题,因此我几乎都只设定30秒而已。

Linux下查看进程打开的文件句柄数:

lsof -n | awk '{print $2}' | sort | uniq -c | sort -nr | more

其中第一列是打开的句柄数,第二列是进程ID

然后可以根据 ID 号来查看进程名。
# ps aef | grep 24204
nginx  24204 24162 99 16:15 ?    00:24:25 /usr/local/nginx/sbin/nginx -s

Linux下查看TCP各状态链接数的方法:

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

TCP连接状态详解
LISTEN: 侦听来自远方的TCP端口的连接请求
SYN-SENT: 再发送连接请求后等待匹配的连接请求
SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认
ESTABLISHED: 代表一个打开的连接
FIN-WAIT-1: 等待远程TCP连接中断请求,或先前的连接中断请求的确认
FIN-WAIT-2: 从远程TCP等待连接中断请求
CLOSE-WAIT: 等待从本地用户发来的连接中断请求
CLOSING: 等待远程TCP对连接中断的确认
LAST-ACK: 等待原来的发向远程TCP的连接中断请求的确认
TIME-WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认
CLOSED: 没有任何连接状态

输入以上命令它会显示例如下面的信息:

TIME_WAIT 814
CLOSE_WAIT 1
FIN_WAIT1 1
ESTABLISHED 634
SYN_RECV 2
LAST_ACK 1

常用的三个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

1、解决 TIME_WAIT 过多的方法(导致TIME_WAIT过多的具体原因请看最后的链接):

i、编辑 /etc/sysctl.conf,添加如下配置

#对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃,不应该大于255,默认值是5,对应于180秒左右时间 
net.ipv4.tcp_syn_retries=2
#net.ipv4.tcp_synack_retries=2
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为300秒
net.ipv4.tcp_keepalive_time=1200
net.ipv4.tcp_orphan_retries=3
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间
net.ipv4.tcp_fin_timeout=30  
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_syn_backlog = 4096
#表示开启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

##减少超时前的探测次数 
net.ipv4.tcp_keepalive_probes=5 
##优化网络设备接收队列 
net.core.netdev_max_backlog=3000

ii、输入 /sbin/sysctl -p 使配置生效

2、解决 TIME_WAIT 过多的办法:

TIME_WAIT状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的。
但是CLOSE_WAIT就不一样了,从上面的图可以看出来,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。个人觉得这种情况,通过服务器内核参数也没办法解决,服务器对于程序抢占的资源没有主动回收的权利,除非终止程序运行。所以如果将大量CLOSE_WAIT的解决办法总结为一句话那就是:查代码。因为问题出在服务器程序里

下面说一种我自己遇到的情况:java程序链接数据库后,没有主动close,导致资源一直占用而出现大量 CLOSE_WAIT

参考:

1、http://www.reistlin.com/blog/123

2、服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值