CloseableHttpClient.close() 导致 Connection pool shut down 的问题

TL;DR;

  • CloseableHttpClient.close() 方法默认行为是关闭 HttpClientConnectionManager
  • 如果多个 CloseableHttpClient 共用了同一个 HttpClientConnectionManager,则第一个请求执行完,其他请求就会爆 Connection pool shut down 异常
  • 备注:httpclient 版本是 4.5.6

1. 背景

某次上线以后,观察到所有的方法调用量都变得特别多,几百倍的增长,但因为当时统一时间段上线逻辑较多,并没有及时定位到问题。

第二天继续排查时,有同事指出 httpclient 连接池 Connection pool shut down 异常增多,于是想到前一天确实使用了相关的方法,代码如下

try {
    @Cleanup CloseableHttpClient client = Requests.getHttpclient(
            15000, 15000, 15000, proxyIpInfo);
    HttpGet httpGet = new HttpGet(url);
    @Cleanup final CloseableHttpResponse execute = client.execute(httpGet);
    return EntityUtils.toByteArray(execute.getEntity());
} catch (IOException e) {
    throw new RuntimeException(e);
}

2. CloseableHttpClientclose 方法

CloseableHttpClient 示例是通过如下代码创建的,其中 CONNECTION_MANAGER 是一个全局静态的共用的 HttpClientConnectionManager 实例。

HttpClients.custom()
      .setConnectionManager(CONNECTION_MANAGER)
      .setDefaultRequestConfig(requestConfig)
      .build();

让我们深入 org.apache.http.impl.client.HttpClientBuilder#build 的源码,看一下如何构建 CloseableHttpClientclose 方法的,核心代码如下,注意看其中我补充的注释

List<Closeable> closeablesCopy = closeables != null ? new ArrayList<Closeable>(closeables) : null;
// 如果 connManagerShared 属性是 false(默认值)
// 那么其 close 方法的逻辑就是关闭 ConnectionManager
if (!this.connManagerShared) {
    if (closeablesCopy == null) {
        closeablesCopy = new ArrayList<Closeable>(1);
    }
    final HttpClientConnectionManager cm = connManagerCopy;
	... ...
    closeablesCopy.add(new Closeable() {

        @Override
        public void close() throws IOException {
            cm.shutdown();
        }

    });
}

3. bug 定位

结合上面两个代码片段,真相已经大白,当 @Cleanup CloseableHttpClient client = Requests.getHttpclient(15000, 15000, 15000, proxyIpInfo); 执行过后,@Cleanup 自动执行 clientclose 方法,这时关闭了共用的全局静态 ConnectionManager

当其他请求获取 CloseableHttpClient 对象并请求时,ConnectionManager 已经被关闭,遂报出 Connection pool shut down 异常

这一过程速度非常快,导致原来函数执行时间缩短很多。因为一次 http 请求 100ms - 数秒,而检测 ConnectionManager 关闭报错只要几 ms。这进而导致了单位时间内,所有函数的执行次数都飙升的很高。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值