在进行服务器维护的时候,发现后台有大量进程处于TIME_WAIT状态。
如:netstat -antp
而此时客户端在连接服务器的时候,出现很卡的现象。重启服务器程序(不重启机器)后,卡顿现象消失,TIME_WAIT状态的程序消失。在网络上查询后,得知TIME_WAIT会占用系统套接口资源,导致客户端在连接服务器的时候,套接字不够用。
那么什么是TIME_WAIT状态?
time_wait状态是指套接字编程中,主动调用close关闭连接一方所处的状态。与TIME_wai类似的还有以下几种状态:
TIME_WAIT 主动调用close一方的状态
CLOSE_WAIT 被动关闭一方的状态,相对于主动调用close方。
FIN_WAIT_1 执行close时,己方发送结束信号的状态
FIN_WAIT_2 被动方同意主动方关闭的状态
一个典型的TCP连接终止可以用图描述如下:
client server
fin M
close FIN_WAIT_1 ----------------->close_wait (被动关闭)
ack m+1
FIN_WAIT_2 <-----------------read 返回0
fin n
TIME_WAIT <----------------- close
ACK N+1
-----------------> closed
首先客户端调用close(发送fin m信号,并处于fin_wait_1状态),因此客户端最后会处于TIME_WAIT状态。
此时服务器端会接收到数据,此时调用read读取数据,read会返回0.表示对方已经执行了关闭操作。此时服务器端可以调用close,向客户端发送fin n信号。
在编程上,客户端调用close以后的所有工作就归操作系统管理了,此时客户端的操作系统会向服务器发送ack n+1的确认信号,让服务器可以完整的关闭整个连接。这样整个连接就正常的关闭了。但此时客户端依然会处于time_wait状态,因为难免最后的ack n+1信号会丢失,需要重发。
以上讲述了客户端先调用close的情形,在实际情况下,服务器端也会由于客户端崩溃或其他机制主动执行close。此时服务器端也会存在一些进程处于TIME_WAIT状态。服务器上如果TIME_WAIT进程较多,就会影响服务器的性能。因为套接字也是一种系统资源,这种资源总是有限的。此时就需要调整系统参数来降低time_wait的进程数(如果是错误的编程的话,请先修改代码错误)。
方法vim /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
修改后使用 /sbin/sysctl -p让参数生效。
如果服务器存在大量的close_wait。则表示代码没有调用close来被动关闭连接。请检查代码是否有对这种情况进行处理。。