客户端产生CLOSE_WAIT状态的解决方案

现象

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

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

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

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

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

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

l 再回到搜索服务所在的服务器,通过netstat一看,发现有400个CLOSE_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(确认)消息说,你关闭吧。

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

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

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

我们尝试过优化Linux中TCP连接参数,减少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的参数,可是客户端还是会出现CLOSE_WAIT的情况,且搜索引擎是使用惠普的Autonomy,闭源的不好入手优化,最后还是通过在客户端实现定时任务定期检查当前连接中状态为leased(拿走但没有返回aviable可用队列中的连接)的连接的数量,检测到该这种连接的数量超过一定数量后,就关闭该连接池,释放所有连接,然后重新初使化该连接池,就可以解决这种问题了,经过测试这种试是可行的。不过曾经考虑到这种方式比较暴力,连可用的连接都给关闭了,本想只关闭那些长久未释放的连接,不过由于连接池没有暴露操作方法,通过反射可以获取到池中的连接,不过由于关联资源较多,操作麻烦,最后没有采用这种方式。

客户端产生CLOSE_WAIT状态的解决方案,布布扣,bubuko.com

时间: 2024-12-21 13:26:03

客户端产生CLOSE_WAIT状态的解决方案的相关文章

客户端产生CLOSE WAIT状态的解决方案

现象 生产环境和测试环境都发现有个外围应用通过搜索服务调用搜索引擎时,偶尔会出现大量的访问超时的问题,通过如下方式进行分析排查: l 首先是拿到搜索服务的JavaCore,发现其堵在HttpClient的发送上面,被堵的连接有数百个,原因是不能够从连接池中获取到连接: l 首先想到的就是连接池没有释放,检查代码,也确实存在着一些调用没有释放连接,特别是在异常的情况下,针对这一部分代码进行修复后,可是一段时间之后还是出现了访问超时的问题: l 考虑到这个外围应用的访问现出问题的时候,其它的外围应用

close_wait状态的产生原因及解决

最近测试环境server由于需要与大量的后台server交互,今天突然发现有大量的close_wait产生,于是仔细研究了一下: 如果我们的服务器程序处于CLOSE_WAIT状态的话,说明套接字是被动关闭的! 因为如果是CLIENT端主动断掉当前连接的话,那么双方关闭这个TCP连接共需要四个packet: 1.Client -> FIN  -> Server 2.Client <- ACK  <- Server   这时候Client端处于FIN_WAIT_2状态:而Server

close_wait状态的产生原因及解决(转)

最近测试环境server由于需要与大量的后台server交互,今天突然发现有大量的close_wait产生,于是仔细研究了一下: 如果我们的服务器程序处于CLOSE_WAIT状态的话,说明套接字是被动关闭的! 因为如果是CLIENT端主动断掉当前连接的话,那么双方关闭这个TCP连接共需要四个packet: 1.Client -> FIN  -> Server   2.Client <- ACK  <- Server   这时候Client端处于FIN_WAIT_2状态:而Serve

关于Socket通讯中的Close_wait状态

关于Socket通讯中的Close_wait状态 文/转 编辑 编者按:使用Socket通讯,有时我们查看端口状态的时候,经常会发现Socket处于close_wait状态,从而影响系统性能,此文或许会给你一些答案. 最近遇到的一个关于socket.close的问题,在某个应用服务器出现的状况(执行netstat -np | grep tcp): tcp        0      0 10.224.122.16:50158         10.224.112.58:8788        

【服务器】一次对Close_Wait 状态故障的排查经历

最近接连听说一台线上服务器总是不响应客户端请求. 登录服务器后查询iis状态,发现应用程序池状态变为已停止. 按经验想,重启后应该就ok,第一次遇到也确实起了作用,当时完全没在意,以为是其他人无意把服务关闭了而已. 但是之后几天几乎每天都出现问题,应用程序池再次成为 已停止 状态.这个情况显然有问题.于是开始排查设置. 线上环境很简单,iis + API应用,数据库在内网上,没有反向代理. 出问题的应用程序池承载了一个基础数据API,查询量极小,数据量也极小,只是因为同事做实现时提过,查询很麻烦

tcp连接出现close_wait状态?可能是代码不够健壮

一.问题概述 今天遇到个小问题. 我们的程序依赖了大数据那边的服务,大数据那边提供了restful接口供我们调用. 测试反映接口有问题,我在本地重现了.找了大数据方的同事,解决了. 刚开始怕对方不认账,就用wireshark抓包了.没想到对方还挺爽快地解决了. 然后我这边重新测试,自己抓包了下,结果反而发现我方程序的一个问题. 下图,是我方和大数据方的交互数据包. 前三个为tcp连接建立,中间(序号4,5,6)为http请求响应,序号7-8为大数据方在请求完毕后关闭连接. 好了,看下面的图:(下

Andriod 程序不能进入Debug状态的解决方案

解决方法: 在AndroidManifest.xml文件中添加android:debuggable字段,如下所示.[java] view plaincopy<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> Andriod 程序不能进入Debug状态的解决方案,布布扣,bubuko.

php处理数据库数据,每处理一个数据返回客户端显示当前状态的方法。

php处理大量数据,每处理一个数据返回客户端显示当前状态的方法. 类似于dedecms生成静态页 想法: 客户端发送请求 服务器端接受请求,开始统计所需处理的数据量 将所需处理数据按一定规则排列,发送到服务器处理端 服务器处理端处理了第一个数据,将处理结果经过一定处理后发送给客户端 客户端接收到结果,自动将处理结果显示并发送到服务器 服务器接收到处理结果 将它转发到服务器处理端 处理端继续处理结果... 循环4-7步骤,直到处理完毕 实验过程: 1.创建数据库和表 create database

关于cocos2dx客户端程序的自动更新解决方案

转载请注明出处:帘卷西风的专栏(http://blog.csdn.net/ljxfblog) 随着手机游戏的不断发展,游戏包也越来越大,手机网络游戏已经超过100M了,对于玩家来说,如果每次更新都要重新下载,那简直是灾难.而且如果上IOS平台,每次重新发包都要审核,劳神费力.所以当前的主流手游都开始提供自动更新的功能,在不改动C++代码的前提下,使用lua或者js进行业务逻辑开发,然后自动更新脚本和资源,方便玩家也方便研发者. 以前做端游的时候,自动更新是一个大工程,不仅要能更新资源和脚本,还要