前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >httpclient连接池管理,你用对了?

httpclient连接池管理,你用对了?

作者头像
加多
发布2020-06-16 15:47:27
4.3K0
发布2020-06-16 15:47:27
举报
文章被收录于专栏:Java编程技术

一、前言

为何要用http连接池那?因为使用它我们可以得到以下好处:

因为使用它可以有效降低延迟和系统开销。如果不采用连接池,每当我们发起http请求时,都需要重新发起Tcp三次握手建立链接,请求结束时还需要四次挥手释放链接。而链接的建立和释放是有时间和系统开销的。另外每次发起请求时,需要分配一个端口号,请求完毕后在进行回收。

使用链接池则可以复用已经建立好的链接,一定程度的避免了建立和释放链接的时间开销。

二、连接池使用

代码语言:javascript
复制
public static void init() {
    //1.创建连接池管理器
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(60000,//1.1
            TimeUnit.MILLISECONDS);
    connectionManager.setMaxTotal(1000);//1.2
    connectionManager.setDefaultMaxPerRoute(50);//1.3
    
    //2.创建httpclient对象
    httpClient = HttpClients.custom()
            .setConnectionManager(connectionManager)//2.1
            .disableAutomaticRetries()//2.2
            .build();
}

如上代码1,我们创建了一个连接池管理器,ClientConnectionPoolManager会维护每个路由维护和最大连接数限制。默认情况下,此实现将为每个给定路由创建不超过2个并发连接,并且总共不超过20个连接。对于许多现实应用程序,这些限制可能证明过于严格。但是,我们可以自由来调整连接限制。

另外构造函数中可以设置持久链接的存活时间TTL(timeToLive),其定义了持久连接的最大使用时间,超过其TTL值的链接不会再被复用。

如上代码1.1我们设置TTL为60s(tomcat服务器默认支持保持60s的链接,超过60s,会关闭客户端的链接)。代码1.2我们设置连接器最多同时支持1000个链接,代码1.3设置每个路由最多支持50个链接。注意这里路由是指IP+PORT或者指域名。如果使用域名来访问则每个域名有自己的链接池,如果使用IP+PORT访问,则每个IP+PORT有自己的链接池。

如上代码2我们基于连接池管理器创建了一个httpClient对象,下面我们就可以使用它发起http请求了。

代码语言:javascript
复制
CloseableHttpResponse response = null;
try {
    
    //3.创建请求对象
    final HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/test");
    
    RequestConfig.Builder builder = RequestConfig.custom();
    builder.setSocketTimeout(3000)//3.1设置客户端等待服务端返回数据的超时时间
           .setConnectTimeout(1000)//3.2设置客户端发起TCP连接请求的超时时间
           .setConnectionRequestTimeout(3000);//3.3设置客户端从连接池获取链接的超时时间
    httpGet.setConfig(builder.build());

    //4.发起请求
    response = httpClient.execute(httpGet);

    //5.成功则解析结果
    if (200 == response.getStatusLine().getStatusCode()) {
        String strResult = EntityUtils.toString(response.getEntity());
        System.out.println(strResult);
    }

} catch (ClientProtocolException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    //5.回收链接到连接池
    if (null != response) {
        try {
            EntityUtils.consume(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

如上代码3创建了一个HttpGet对象,并创建RequestConfig对象来设置请求参数。

代码3.3设置客户端从连接池获取链接的超时时间,如果在该时间内没能从连接池获取到连接,则抛出ConnectionPoolTimeoutException异常。

代码3.2设置客户端发起TCP连接请求的超时时间,也就是创建TCP连接时候等待的时间,如果该时间内还没完成TCP三次握手,则抛出ConnectTimeoutException异常。

代码3.1设置客户端等待服务端返回数据的超时时间,也就是请求发出去后,如果等待该时间服务端还没返回结果,则抛出SocketTimeoutException异常。

代码4则发起http请求,代码5发现请求OK,则使用自带工具类EntityUtils.toString解析返回值(内部读取流结束后,会自动返还链接到连接池)

代码5则当请求结束后做一个兜底链接归还(如果返回状态值不是200,则需要在这里处理链接归还),注意这里不能调用response.close();因为其不是归还链接到连接池,而是关闭链接。

三、总结

本文简单介绍了如何使用链接池,使用连接池时需要注意合理设置最大链接数和每个路由(比如域名)对应的链接数,另外特别需要注意设置setConnectionRequestTimeout参数,其决定了从连接池拿链接的超时时间。

另外需要注意使用链接池时,请求结果回来后,要记得归还链接,如果链接得不到归还,则首先会把连接池打满,然后新来的请求从连接池拿不到链接会抛出ConnectionPoolTimeoutException异常。

另外归还链接不要调用response对象的close()方法,因为其是关闭链接,而不是把链接返回到链接池。需要调用EntityUtils中方法或者自己从response.getEntity().getContent()获取流,读取完毕(读取完毕后会自动归还链接)或者不读取时主动调用流的close()来显示归还链接到连接池。

知识扩展: 自http1.1后,http默认支持keep-alive。对于Tomcat服务器默认保持客户端的链接60s,我们httpclient这边也可以设置链接存活时间,最终链接的存活时间是取两者中最小的。

对于过期链接的处理,当Tomcat主动关闭链接时,httpclient 4.4之前是每次在复用链接前进行检查链接是否可用,http4.4后,是自上次使用连接以来所经过的时间超过已设置的超时时(默认超时设置为2000ms),才检查连接。如果发现链接不可用,则从链接池剔除,在创建新的链接。

当客户端设置的TTL到期时(此时Tomcat容器没有主动关闭链接时),在每次发起请求时,会检查链接是否已经过期,如果过期(虽然链接本身是可以用的),则也主动关闭链接,然后从链接池剔除,在创建新的链接。

另外我们可以实现自己的ConnectionKeepAliveStrategy来给不同的域名设置不同的链接存活策略。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、连接池使用
  • 三、总结
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档