TCP协议端口,TIME_WAIT状态跟CLOSE_WAIT状态的问题

 

今天来公司,碰到一件坑的事,发现app后台节点其中的一个节点,不再接着工作,监控方面也没有报警,因为监控只是监控端口,看来还要优化一下监控规则

我去了那个节点的服务器上查看了一下,发现网络连接全是CLOSE_WAIT状态,让我感到无奈,只能去网上恶补了关于TCP协议和TIME_WAIT跟CLOSE_WAIT的知识

 

关于TCP协议的连接状态,分为以下几种

LISTENING状态

        提供某一种服务,用于侦听远方TCP端口,当提供的服务没有被连接时,就会处于LISTENING状态,等待连接

SYN_SENT状态

        SYN_SENT是客户端状态,客户端调用connect发送一个SYN请求建立连接,在发送连接请求后等待匹配的连接请求。

SYN_RECEIVED状态

        SYN_RECEIVED是服务端状态,在收到和发送一个连接请求后,等待对方对连接请求的确认,当服务器收到客户端发送的同步信号时,将标志位ACK和SYN置1发送给客户端,此时服务          器端处于SYN_RCVD状态,如果连接成功了就变为ESTABLISHED,正常情况下SYN_RCVD状态非常短暂。

ESTABLISHED状态

        ESTABLISHED状态是表示两台机器正在传输数据

FIN-WAIT-1状态

        等待远程TCP连接中断请求,或先前的连接中断请求的确认,主动关闭端应用程序调用close,TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态

FIN-WAIT-2状态

        从远程TCP等待连接中断请求,主动关闭端接到ACK后,就进入了FIN-WAIT-2 .这是在关闭连接时,客户端和服务器两次握手之后的状态,是著名的半关闭的状态了,在这个状态下,应          用程序还有接受数据的能力,但是已经无法发送数据,但是也有一种可能是,客户端一直处于FIN_WAIT_2状态,而服务器则一直处于WAIT_CLOSE状态,而直到应用层来决定关闭状态

CLOSE-WAIT状态

        等待从本地用户发来的连接中断请求 ,被动关闭端TCP接到FIN后,就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序),并进入CLOSE_WAIT

CLOSING状态

        等待远程TCP对连接中断的确认,处于此种状态比较少见

LAST-ACK状态

        等待原来的发向远程TCP的连接中断请求的确认,被动关闭端一段时间后,接收到文件结束符的应用程序将调用CLOSE关闭连接,TCP也发送一个 FIN,等待对方的ACK.进入LAST-ACK

TIME-WAIT状态

        在主动关闭端接收到FIN后,TCP就发送ACK包,并进入TIME-WAIT状态,等待足够的时间以确保远程TCP接收到连接中断请求的确认,很大程度上保证了双方都可以正常结束,但是也存在          问题,须等待2MSL时间的过去才能进行下一次连接

CLOSED状态

        被动关闭端在接受到ACK包后,就进入了closed的状态,连接结束,没有任何连接状态。

 

最常用的状态有三个

ESTABLISHED:表示正在通信

TIME_WAIT:表示主动关闭

CLOSE_WAIT:表示被动关闭

 

以下附上二张图

 

 

 

处理TIME_WAIT状态

TIME_WAIT是主动关闭连接的一方保持的状态。对于服务器来说,本身就是客户端,在完成一次连接传输任务后,就主动发起关闭连接,从而进入TIME_WAIT状态,状态保持2分钟,过了这时间之后,彻底回收资源

这设计思想是来由TCP/IP的设计者设计的,主要有以下二方面的考虑

  1. 防止上一次连接中的包,迷路后重新出现,影响新连接,只有经过2分钟后,上一次连接中所有的数据才会完全消失
  2. 可靠的关闭TCP连,在主动关闭方发送的最后一个akc(fin),有可能丢失,这时被动方会重新发送akc(fin),如果这时主动方处于CLOSED状态,就会响应rst而不是akc(fin),所以主动方要处于TIME_WAIT状态,而不能是CLOSED状态,另外这么设计TIME_WAIT会定时的回收资源,并不会占用很大的资源,除非短时间内接受了大量请求或攻击

 

如果服务器因TIME_WAIT连接状态过多,影响到服务器的本身速度跟业务

解决方法,就是让服务缩短回收的时间,让快速回收和重用资源

修改/etc/sysctl.conf文件

net.ipv4.tcp_syn_retries=2
#对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃,不应该大于255,默认值是5,对应于180秒左右时间

#net.ipv4.tcp_synack_retries=2
##注释这行配置行

net.ipv4.tcp_keepalive_time=1200
net.ipv4.tcp_orphan_retries=3
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为300秒

net.ipv4.tcp_fin_timeout=30
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间

net.ipv4.tcp_max_syn_backlog = 4096
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

net.ipv4.tcp_syncookies = 1
#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭

net.ipv4.tcp_tw_reuse = 1
#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭

net.ipv4.tcp_tw_recycle = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭

net.ipv4.tcp_keepalive_probes=5 
##减少超时前的探测次数 

net.core.netdev_max_backlog=3000
##优化网络设备接收队列 


重要说明
net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle
##开启都是为了回收处于TIME_WAIT状态的资源。

net.ipv4.tcp_fin_timeout
##这个时间可以减少在异常情况下服务器从FIN-WAIT-2转到TIME_WAIT的时间。

net.ipv4.tcp_keepalive_*
##一系列参数,是用来设置服务器检测连接存活的相关配置

以上的配置,来源于网上

 

修改完成后,执行以下的命令,让配置生效

/sbin/sysctl -p

 

 

处理CLOSE_WAIT状态

如果连接一直保持在CLOSE_WAIT状态,那么只有一种情况,就是对方关闭连接之后,服务器程度自己没有发出ack信号。

也就是说,在对方关闭连接后,程序没有检测到,或者程序就不知道在这时候需要关闭连接,于是这个资源就一直被程度占着。

如果遇到CLOSE_WAIT状态过多的情况,可以考虑一下修改一下内核参数,如果内核参数解决不了,就只会是程序的问题,查代码

本人对CLOSE_WAIT状态处理理解不够深度,如果网友有更好的处理解决方案,麻烦请联系我,让我学习一下。

 

 

发表评论:

共有 0 条评论

 Top