1 通常缘由都是TCP链接没有调用关闭方法。须要应用来处理网络连接关闭。 2 对于Web请求出现这个缘由,常常是由于Response的BodyStream没有调用Close. 好比Widnows下: 使用HttpWebRequest 必定要保证GetRequestStream和GetResponse对象关闭,不然容易形成链接处于CLOSE_WAIT状态 3 TCP的KeepLive功能,可让操做系统替咱们自动清理掉CLOSE_WAIT的链接。 可是KeepLive在Windows操做系统下默认是7200秒,也就是2个小时才清理一次。每每知足不了要求。能够调小该数值。 Windows下的调整方法为 HKEY_LOCAL_MACHINE/CurrentControlSet/Services/Tcpip/Parameters下的如下三个参数: KeepAliveInterval,设置其值为1000 www.2cto.com
KeepAliveTime,设置其值为300000(单位为毫秒,300000表明5分钟) TcpMaxDataRetransmissions,设置其值为5 Close_Wait引起的问题: Close_Wait会占用一个链接,网络可用链接小。数量过多,可能会引发网络性能降低,并占用系统非换页内存。 尤为是在有链接池的状况下(好比HttpRequest) 会耗尽链接池的网络链接数,致使没法创建网络链接服务器
----引自红黑联盟的《TCP的状态兼谈Close_Wait和Time_Wait的状态》网络
生产环境和测试环境都发现有个外围应用经过搜索服务调用搜索引擎时,偶尔会出现大量的访问超时的问题,经过以下方式进行分析排查: l 首先是拿到搜索服务的JavaCore,发现其堵在HttpClient的发送上面,被堵的链接有数百个,缘由是不可以从链接池中获取到链接; l 首先想到的就是链接池没有释放,检查代码,也确实存在着一些调用没有释放链接,特别是在异常的状况下,针对这一部分代码进行修复后,但是一段时间以后仍是出现了访问超时的问题; l 考虑到这个外围应用的访问现出问题的时候,其它的外围应用调用搜索服务是没有问题的,所以肯定当前搜索服务尚未挂; l 不一样的外围应用可能调用的后台搜索引擎是不同的,难道是该外围应用对应的搜索引擎出现了问题?不过通过对该搜索引擎进行分析,该搜索引擎自己是正常的,可是有一个奇怪的现象,在外围应用调用搜索服务发生超时时,搜索引擎自己没有接受到任何请求; l 也就是说经搜索服务的请求都没有提交到该搜索引擎上,难道是搜索服务与该搜索引擎之间的链接有问题?经过网络排查,使用Ping和Telnet进行正向和反向肯定,从搜索服务和搜索引擎之间的网络是正常的,且端口也能够正常访问; l 再回到搜索服务所在的服务器,经过netstat一看,发现有400个CLOSE_WAIT与该搜索引擎相关的链接,这个数字刚好是应用中设置的单个Route所可以链接的最大链接数。tcp
分析到此,问题就明朗了,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可用队列中的链接)的链接的数量,检测到该这种链接的数量超过必定数量后,就关闭该链接池,释放全部链接,而后从新初使化该链接池,就能够解决这种问题了,通过测试这种试是可行的。不过曾经考虑到这种方式比较暴力,连可用的链接都给关闭了,本想只关闭那些长久未释放的链接,不过因为链接池没有暴露操做方法,经过反射能够获取到池中的链接,不过因为关联资源较多,操做麻烦,最后没有采用这种方式。测试