(干货)一次httpclient的close_wait问题的探讨

 

从图中可以看出,如果客户端被动关闭连接,且没有向服务器端发送FIN,则会一直处于CLOSE_WAIT状态。

处理服务器在处理完请求,与后端Nginx之间的连接仍然保持着CLOSE_WAIT状态,个数为256(最大连接数)。

        原因:后端Nginx设置keep-alive长连接,在处理完处理服务器请求后,由于keep-alive长连接超时设置Nginx服务器主动关闭了连接,处理服务器端被动关闭,与后端Nginx间的连接处于CLOSE_WAIT状态。根据查阅资料,大量的CLOSE_WAIT连接会占用系统资源,会造成连接阻塞,当新的请求到达时无法建立新的连接,真的是这样吗?为了验证这一说法,做了以下实验:

      (1)为了便于观察端口的变化,将后端Nginx keep-alive最大连接数设置为10。

      (2)向系统发起10个请求,如图所示建立起10个连接后处于CLOSE_WAIT状态。

      (3)再向系统发起第11个请求时,原来的62454端口的连接断开。 

      (4)分配新的端口62470建立新的连接。

验证结论:系统虽然存在大量的CLOSE_WAIT,但它并不会造成连接阻塞,在新的请求到达时,旧的CLOSE_WAIT连接会断开。这是因为HttpClient有这样的机制,会自动清理CLOSE_WAIT状态的连接。

然而,在测试中还遇到了另外一个CLOSE_WAIT问题却造成了连接阻塞,这是为什么呢?请看接下来问题2的分析。

向处理服务器发起大量对象名不存在的请求,处理服务器与后端Nginx之间也保持CLOSE_WAIT状态,但是新的请求发起时,原来CLOSE_WAIT连接并没有断开,当达到Nginx设置的最大连接数256时,系统将不能再建立连接处理新的请求。为了定位原因,做了以下实验。

 (1) 向系统发起对象名不存在的一个错误请求,处理服务器与后端Nginx之间的建立连接

 (2)Nginx在keep-alive超时后主动关闭连接,处理服务器与Nginx连接状态变为CLOSE_WAIT

 (3)再次向系统发起对象名不存在的错误请求,旧的连接一直保持CLOSE_WAIT状态  

根据以上结果可以看出,CLOSE_WAIT状态的连接并没有被断开,这和问题1的验证结果是相悖的。它们的区别是什么呢? 

 (4)向NOS服务器再发起一个正确请求,如下所示,处理服务器与Nginx之间的连接由ESTABLISHED状态最后变为CLOSE_WAIT。

 (5)再发起新的正确请求,原来的57826端口的连接断开,在57846端口建立新的连接。

 HttpClient有清理CLOSE_WAIT状态的机制,那为什么错误的请求产生的CLOSE_WAIT不能被清理呢?查看处理服务器使用HttpClient代码,发现在处理异常请求部分的代码中,没有读取后端tobie处理结果返回body的操作,而根据Httpclient的处理机制,只有在读body操作后才会触发HttpClient Manager回收连接,否则会被认为该连接一直在处理请求。因此在处理异常请求部分的代码中增加response. getEntity().consumeContent()方法读body操作。

 

posted @ 2017-01-16 16:13  安大叔  阅读(1196)  评论(0编辑  收藏  举报