服务器CLOSE_WAIT请求太多的问题

上周因为调用某个服务不可用,导致服务器出现了大量的CLOSE_WAIT的tcp链接,导致tomcat出现了假死的情况.大量的tcp请求一直卡着,其他请求进来tomcat已经不能提供服务了.
头一次遇到这样的情况,然后查了一下这个CLOSE_WAIT的资料.发现CLOSE_WAIT其实是tcp的一种状态,我们先来看张图了解一下tcp的各个状态.

状态:
CLOSED: 没有任何连接状态,是tcp状态的起点和终点(这时候服务器啥都没干)
LISTEN: 监听来自远方的TCP端口的连接请求
SYN_SENT: 第一次收到请求的状态,由客户端发送给服务端,成功后进入到SYN_RECEIVED,失败的直接CLOSED
SYN_RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认
ESTABLISHED: 三次握手完成,已经简历一个打开的连接,这个时候就可以发送数据了
FIN_WAIT_1: 等待远程TCP连接中断请求,或先前的连接中断请求的确认
FIN_WAIT_2: 接受了远端的ACK确认之后,从等待连接中断请求
CLOSE_WAIT: 等待从本地用户发来的连接中断请求
CLOSING: 等待远程TCP对连接中断的确认
LAST_ACK: 等待原来的发向远程TCP的连接中断请求的确认
TIME_WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认

对照着客户端和服务端的状态变化来理解消化下

问题分析:

看完上面tcp的各个状态变化过程之后,应该有了一个大致的了解 ,给我们看下服务器上的tcp请求状态情况,可以使用命令

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

当时检测出来CLOSE_WAIT 大概有1000左右,这个和httpClient设置的maxConnTotal的数量查不多.

tcp请求关闭包含主动关闭和被动关闭,当服务端收到了中断的seq和ack后,就处于CLOSE_WAIT状态,
,照理说应该立马发送ack.但是处于CLOSE_WAIT说明服务端没有发送ack到客户端(其实这里实际上是远端服务端).导致这种情况的可能是
服务端忙于处理数据或者是其他操作,导致没有发出去ack命令.

我检查了发送请求的代码response等流都是正常关闭了,那么我们看下是不是其他问题导致,发现当接收到响应的时候,如果状态不是200,请求就直接返回了.大概类似于这样:

if (response.getStatusLine() == HttpStatus.SC_OK) {
 // 具体处理
}

如果不等于200的情况没有处理,修改后

if (response.getStatusLine() == HttpStatus.SC_OK) {
 // 具体处理
} else {
  httpRequest.abort();
 // 中断状态不对的请求
}

然后我们在etc/sysctl.conf加上如下三个参数:
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_time = 1800 // 单位是秒 就是30分钟

然后sysctl -p让配置生效.

1.tcp_keepalive_time
当keepalive起用的时候,TCP发送keepalive消息的频度,就是说空闲这个时间然后去确认连接是否还在,缺省是2小时。
2.tcp_keepalive_intvl
当探测没有确认时,重新发送探测的频度。缺省是75秒。
3.tcp_keepalive_probes
在认定连接失效之前,发送多少个TCP的keepalive探测包

我只做了这两个操作就CLOSE_WAIT数量就下来了,还有其他可能性也会导致这样的情况.可以参考下面的资料

参考资料:

1.https://www.cnblogs.com/jessezeng/p/5616518.html
2.https://blog.csdn.net/shootyou/article/details/6615051

猜你喜欢

转载自blog.csdn.net/sc9018181134/article/details/100678894