client产生CLOSE_WAIT状态的解决方式

现象

生产环境和測试环境都发现有个外围应用通过搜索服务调用搜索引擎时。偶尔会出现大量的訪问超时的问题,通过例如以下方式进行分析排查:

l 首先是拿到搜索服务的JavaCore。发现其堵在HttpClient的发送上面,被堵的连接有数百个,原因是不可以从连接池中获取到连接。

l 首先想到的就是连接池没有释放,检查代码,也确实存在着一些调用没有释放连接。特别是在异常的情况下,针对这一部分代码进行修复后。但是一段时间之后还是出现了訪问超时的问题;

l 考虑到这个外围应用的訪问现出问题的时候,其他的外围应用调用搜索服务是没有问题的,因此确定当前搜索服务还没有挂;

l 不同的外围应用可能调用的后台搜索引擎是不一样的。难道是该外围应用相应的搜索引擎出现了问题?只是经过对该搜索引擎进行分析。该搜索引擎本身是正常的,但是有一个奇怪的现象,在外围应用调用搜索服务发生超时时。搜索引擎本身没有接受到不论什么请求;

l 也就是说经搜索服务的请求都没有提交到该搜索引擎上。难道是搜索服务与该搜索引擎之间的连接有问题?通过网络排查,使用PingTelnet进行正向和反向确定,从搜索服务和搜索引擎之间的网络是正常的,且port也可以正常訪问。

l 再回到搜索服务所在的server,通过netstat一看。发现有400CLOSE_WAIT与该搜索引擎相关的连接。这个数字恰好是应用中设置的单个Route所可以连接的最大连接数。

 

分析到此,问题就明朗了,HttpClient连接池的中创建连接数已经达到了最大数字。不可以创建新的连接了。已经创建的连接都是在等待关闭(CLOSE_WAIT)的状态,没有被放回到可用的连接池中,不可以用于处理新的连接请求,因而全部的请求都是堵在了从连接池中获取连接哪里。

要解决问题,首先须要知道CLOSE_WAIT产生的原因,才可以解决该问题。或者降低该问题的发生。

TCP连接关闭时须要四次握手才可以完毕。例如以下图所看到的:

 

产生CLOSE_WAIT状态的一方。是属于被动关闭的一方,用简单的话对解释上图(主动关闭方为A,被动关闭方为B):

A发一条FIN(关闭)请求给B。说我要关闭了。

B回应一条ACK(确认)请求给A,说我知道了。你关吧,此时B就会进行CLOSE_WAIT状态;

B发送一条FIN(关闭)请给A,说我要关闭了。

A收到发送一条ACK(确认)消息说,你关闭吧。

 

上面四次握手完毕后,两方的连接就都关闭了,但是这里在client产生了CLOSE_WAIT现象,首先可以确定的是服务端主动关闭的连接,且client没有给服务端发送关闭的请求(第三次握手请求),就会一直处在CLOSE_WAIT的状态。但是client为什么不向服务端发送关闭的请求。它当时在忙什么呢,难道应用在关闭前有哪么多事情要做?还有就是为什么服务会主动关掉client的这么多连接?

有人说这可能是服务端在调用关闭时,而client正在运行RECV(数据接收),这时候有可能服务端发送的FIN包client接收出错。就是由TCP代回了一个ACK包,所以client就会处在CLOSE_WAIT的状态中。因而建议推断RECV时是否出错。假设出错就主动关闭连接。这样就行防止没有接收到FIN包。

也有人说这是因为client请求服务端时,超时就有可能出现这样的情况,我对这样的情况做了实验,分别启动了client和服务端。在服务端中暴露一个超时的服务接口,在client中通过POST的方式调用,然后再通过第三方工具调用client去调用服务端的超时接口,測试分别在Linux以及Windows平台进行了測试,但是经过100万个连接超时的请求后,client没有出现CLOSE-WAIT的现象,仅仅有服务端才出现了CLOSE-WAIT,而且都会正常的关闭。

我们尝试过优化LinuxTCP连接參数,降低TCP的连接时间以及添加连接的可用性,例如以下:

sysctl -w net.ipv4.tcp_timestamps=0 

sysctl -w net.ipv4.tcp_tw_reuse=1 

sysctl -w net.ipv4.tcp_tw_recycle=1 

sysctl -w net.ipv4.tcp_fin_timeout=30 

sysctl -w net.ipv4.tcp_keepalive_time=1800 

sysctl -w net.ipv4.tcp_rmem="4096 87380 8388608" 

sysctl -w net.ipv4.tcp_wmem="4096 87380 8388608" 

sysctl -w net.ipv4.tcp_max_syn_backlog=4096 

也优化了HttpClient的參数。但是client还是会出现CLOSE_WAIT的情况,且搜索引擎是使用惠普的Autonomy,闭源的不好入手优化,最后还是通过在client实现定时任务定期检查当前连接中状态为leased(拿走但没有返回aviable可用队列中的连接)的连接的数量。检測到该这样的连接的数量超过一定数量后,就关闭该连接池,释放全部连接,然后又一次初使化该连接池,就行解决这样的问题了,经过測试这样的试是可行的。只是以前考虑到这样的方式比較暴力,连可用的连接都给关闭了,本想仅仅关闭那些长久未释放的连接,只是因为连接池没有暴露操作方法,通过反射可以获取到池中的连接,只是因为关联资源较多。操作麻烦,最后没有採用这样的方式。

转载于:https://www.cnblogs.com/zhchoutai/p/8327406.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值