最近,公司的接口服务器(客户端,向外发送数据)频繁出现了connect timeout 以及readtime out 的情况,经过运维平台检测,并没有网络延时的情况。于是,开始怀疑连接池出了问题。

  使用linux命令: netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'  可以清楚的看到tcp各个状态下的连接数。

  

  如图: CLOSE_WAIT 数目大的惊人,问题就出在了这里:这个级别的TIME_WAIT是没有问题的, linux的句柄数(https://blog.csdn.net/shootyou/article/details/6579139)有限,大量的CLOSE_WAIT占去了过多的连接数,导致其他连接异常。

  据查:

  tcp连接三次握手,四次挥手。

  

    这其中,我们比较关注的状态有三个: ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

    其中:ESTABLISHED  无需多言,  TIME_WAIT  的存在是:

  1. 防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)
  2. 可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。

  

值 得一说的是,对于基于TCP的HTTP协议,关闭TCP连接的是Server端,这样,Server端会进入TIME_WAIT状态,可 想而知,对于访 问量大的Web Server,会存在大量的TIME_WAIT状态,假如server一秒钟接收1000个请求,那么就会积压 240*1000=240,000个 TIME_WAIT的记录,维护这些状态给Server带来负担。当然现代操作系统都会用快速的查找算法来管理这些 TIME_WAIT,所以对于新的 TCP连接请求,判断是否hit中一个TIME_WAIT不会太费时间,但是有这么多状态要维护总是不好。
HTTP协议1.1版规定default行为是Keep-Alive,也就是会重用TCP连接传输多个 request/response,一个主要原因就是发现了这个问题。  

    也就是说HTTP的交互跟上面画的那个图是不一样的,关闭连接的不是客户端,而是服务器,所以web服务器也是会出现大量的TIME_WAIT的情况的。这也说清楚了,为什么我的客户端服务器会出现大量CLOSE_WAIT的情况。

    然后,我又在windows 端实时测试(netstat同样适用),的确,我所使用的HttpClient4 在每次接口发送完毕都会产生一个CLOSE_WAIT。这是为什么呢,使用连接池,是为了连接可以复用,而现在的情况确是相反的。

    经查,HttpClient4为了连接复用使用的都是长连接,Response的Header中默认Connection是Keep-alive即连接不会关闭,以便下次请求相同网站的时候进行复用,这是产生CLOSE_WAIT连接的原因所在。所以我猜测HttpClient4 故意留住CLOSE_WAIT

复用该连接。不会复用? 是不是我的对象创建的有问题?于是改了单例:

    

public class HttpApacheClient {private static class SingletonHandler{private static HttpApacheClient singleton = new HttpApacheClient();}private HttpApacheClient(){}public static HttpApacheClient getInstance(){return SingletonHandler.singleton;}private static Logger logger = LoggerFactory.getLogger(HttpApacheClient.class);private final HttpClientConnectionManager manager = builderPoolConnectionManager() ;  //定义连接池管理变量ResponseHandler<String> responseHandler = new ResponseHandler<String>() {@Overridepublic String handleResponse(final HttpResponse response)throws ClientProtocolException, IOException {int status = response.getStatusLine().getStatusCode();if (status >= 200 && status < 300) {HttpEntity entity = response.getEntity();if (entity == null) throw new BusinessException(RESULT_LOG_ERROR);String content =  EntityUtils.toString(entity);logger.info("the log back :"+content);JSONObject jsonObject = JSON.parseObject(content);Integer returnStatus = (Integer)jsonObject.get("status");if (returnStatus !=200) throw new BusinessException(RESULT_LOG_ERROR,content);return content;} else {throw new ClientProtocolException("Unexpected response status: " + status);}}};public HttpClientConnectionManager builderPoolConnectionManager(){final SSLContext context = SSLContexts.createSystemDefault();final HostnameVerifier verifier = new DefaultHostnameVerifier() ;//自定义注册器,既可以发送http请求,也可以发送https请求final Registry<ConnectionSocketFactory> register = RegistryBuilder.<ConnectionSocketFactory>create().register("http" , PlainConnectionSocketFactory.INSTANCE).register("https" , new SSLConnectionSocketFactory(context ,verifier)).build() ;PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(register);poolingHttpClientConnectionManager.setMaxTotal(200);  //设置连接池的最大连接数poolingHttpClientConnectionManager.setDefaultMaxPerRoute(poolingHttpClientConnectionManager.getMaxTotal());  //一个路由的最大连接数return poolingHttpClientConnectionManager ;}public HttpClient buildHttpClient(){RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(3000)  //从池中获取请求的时间.setConnectTimeout(2000)   //连接到服务器的时间.setSocketTimeout(5000).build(); //读取信息时间
CloseableHttpClient build = HttpClients.custom().setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE).setDefaultRequestConfig(config).setConnectionManagerShared(true).setConnectionManager(manager).build();return build ;}public static String postJson(String url, List<NameValuePair> params) throws Exception {String urlHead = (String) BeanHelper.getConfig("url");url = urlHead+url;logger.info("url "+url+";"+params);HttpApacheClient utils = getInstance();HttpClient httpClient = null;HttpPost httpPost = null;try {httpClient = utils.buildHttpClient();httpPost = new HttpPost(url);httpPost.setEntity(new UrlEncodedFormEntity(params,"UTF-8"));httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");return httpClient.execute(httpPost, utils.responseHandler);}catch (Exception e){if (httpPost!=null) httpPost.abort();//异常时 关闭连接throw  e;}}}
}

  问题得以解决。

  水比较深,未完待续。

转载于:https://www.cnblogs.com/caoyusongnet/p/9087633.html

HttpClient4 TIME_WAIT和CLOSE_WAIT相关推荐

  1. TCP端口状态说明ESTABLISHED、TIME_WAIT、 CLOSE_WAIT

    一. 首先说下tcp端口的几种状态: 1.LISTENING状态 FTP服务启动后首先处于侦听(LISTENING)状态. 2.ESTABLISHED状态 ESTABLISHED的意思是建立连接.表示 ...

  2. 系统调优,你所不知道的TIME_WAIT和CLOSE_WAIT

    https://my.oschina.net/fdhay/blog/638631 高性能网络 | 你所不知道的TIME_WAIT和CLOSE_WAIT 2016-02-18 大房 大房说 本文是我将最 ...

  3. java项目close wait_服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

    昨天解决了一个HttpClient调用错误导致的服务器异常,具体过程如下: 里头的分析过程有提到,通过查看服务器网络状态检测到服务器有大量的CLOSE_WAIT的状态. 在服务器的日常维护过程中,会经 ...

  4. 再谈应用环境下的TIME_WAIT和CLOSE_WAIT

    昨天解决了一个HttpClient调用错误导致的服务器异常,具体过程如下: http://blog.csdn.net/shootyou/article/details/6615051 里头的分析过程有 ...

  5. TCP端口状态 LISTENING、ESTABLISHED、TIME_WAIT及CLOSE_WAIT详解,以及三次握手,滑动窗口

    参考文章:端口状态 LISTENING.ESTABLISHED.TIME_WAIT及CLOSE_WAIT详解,以及三次握手,滑动窗口

  6. 应用环境下的TIME_WAIT和CLOSE_WAIT

    转载自:http://blog.csdn.net/shootyou/article/details/6622226 昨天解决了一个HttpClient调用错误导致的服务器异常,具体过程如下: http ...

  7. TCP连接(Time_Wait、Close_Wait)说明

    修改Time_Wait和CLOSE_WAIT时间 修改Time_Wait参数的方法 (在服务端修改) Windows下在HKEY_LOCAL_MACHINE/SYSTEM/CurrentControl ...

  8. TIME_WAIT和CLOSE_WAIT

    先看下三次握手四次挥手的状态变化: 通常会遇到下面两种情况: 服务器保持了大量TIME_WAIT状态 服务器保持了大量CLOSE_WAIT状态 因为linux分配给一个用户的文件句柄是有限的,而TIM ...

  9. 网络 TCP的头部 3次握手和4次挥手 出现大量TIME_WAIT或CLOSE_WAIT的原因及解决办法

    TCP头部结构 16位源端口:标识发送方端口 16位目的端口:标识接受方端口 32位序列号:数据按照序列号传输,如果接收方接受后的数据序列号出现错误,可以根据此序号重新排列 32位确认号:接受方接受到 ...

最新文章

  1. 是时候了解一下Serverless了
  2. Windows server 2003/2008更改远程桌面端口脚本
  3. sql item_map
  4. 对于按成本组件结构(要素)还原
  5. 一种绕过Android P对非SDK接口限制的简单方法
  6. linux awk列数据处理工具使用示例
  7. rog live service是什么_王者荣耀五周年好礼送不停,玩游戏还能白嫖ROG游戏手机3?...
  8. 怎么做 慢充 话费_高佣联盟充值话费省钱小技巧教程
  9. Tornado web 框架
  10. linux系统中使用pycharn,在pycharm中使用linux控制台
  11. 坚果云 operationnotallowed webdav_妙用 NAS 服务,将你的知识库和音乐库搬上「云」...
  12. python编程软件免费吗_MRT7-Python编程软件
  13. uva11054 - Wine trading in Gergovia(等价转换,贪心法)
  14. 一篇文章助你深入理解zookeeper
  15. linux软连接j,Linux(ubuntu)安装JLink 驱动
  16. mysql杀掉sql语句,Mysql使用kill命令解决死锁问题(杀死某条正在执行的sql语句)
  17. Re:LieF ~親愛なるあなたへ~ 后感
  18. android启动百度地图应用并开始导航,android打开外部地图导航(百度、高德、腾讯)...
  19. v-for与v-if为什么不能同时用?
  20. 锐捷睿易RAP100全新上市 WALL AP也有超高性能

热门文章

  1. sqrt numpy_NumPy sqrt()–矩阵元素的平方根
  2. java 生成csr_Java以编程方式生成CSR
  3. log4j 配置文件示例_Log4j2示例教程–配置,级别,附加程序
  4. this 改变this的指向
  5. hadoop生态搭建(3节点)-07.hive配置
  6. 若只有4KB内存可用,该如何打印数组中所有重复的元素
  7. 【JSP笔记】第四章 JSP内置对象【下】
  8. RabbitMQ(7)-发后即忘模型
  9. Apache Tomcat部署多个项目
  10. apache的站点安全1