美文网首页
HttpClient ConnectionPoolTimeout

HttpClient ConnectionPoolTimeout

作者: Yellowtail | 来源:发表于2019-05-05 21:13 被阅读0次

概述

今天在使用HttpClient 进行 远程调用测试
调用两个服务,一个在同一个集群,一个在不同的集群
想测试一下,看下不同集群寻址耗时到底有多大
没想到,这个过程中,遇到了很多问题,一一解决之后,在此记录一下,分享出来

无响应

第一版代码

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

private static final HttpClient CLIENT = HttpClientBuilder.create().build;

public static void main(String[] args) throws Exception {
    HttpGet httpGet = new HttpGet(url);

    long begin = System.currentTimeMillis();
    HttpResponse response = CLIENT.execute(httpGet);
    long gap = System.currentTimeMillis() - begin;

    int statusCode = response.getStatusLine().getStatusCode();
    LOGGER.info("type {}, response code {}, gap {}", type, statusCode, gap);
}

代码写好之后,在postman里配置好,随手点了两下,发现点多了就有点卡,
现象就是过了好久都没有响应

猜测是不是网络出了问题,超时了,于是网上搜了搜,加了三个超时时间

博客

对client 更新一下

private static final HttpClient CLIENT;
static {
    RequestConfig config = RequestConfig.custom()
            .setConnectionRequestTimeout(1000)    //从连接池中获取连接的超时时间
            .setConnectTimeout(300)               // 与服务器连接超时
            .setSocketTimeout(300)                // 读取服务器返回的数据 超时
            .build();
    
    CLIENT = HttpClientBuilder.create()
        .setDefaultRequestConfig(config)
        .build();
}

第一次 ConnectionPoolTimeoutException

client 各种超时时间设置好后,的确不再很长时间无响应,但是点到第三次直接就抛异常 ConnectionPoolTimeoutException

org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:286)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:263)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)

搜了一圈,发现这个异常是因为 HttpClient 默认的 连接池 数量为 2,当连接池用完之后,拿不到连接且达到超时阈值,就会抛异常
那么我就把这个数量改大点,并且主动调用 abort 方法
相关博客
https://blog.csdn.net/shootyou/article/details/6615051
https://blog.csdn.net/shootyou/article/details/6415248

代码更新
client

private static final HttpClient CLIENT;
static {
    RequestConfig config = RequestConfig.custom()
            .setConnectionRequestTimeout(1000)    //从连接池中获取连接的超时时间
            .setConnectTimeout(300)               // 与服务器连接超时
            .setSocketTimeout(300)                // 读取服务器返回的数据 超时
            .build();
    
    //参数含义参考 下面两个博客
    //https://blog.csdn.net/shootyou/article/details/6615051
    //https://blog.csdn.net/shootyou/article/details/6415248
    
    CLIENT = HttpClientBuilder.create()
        .setDefaultRequestConfig(config)
        .setMaxConnTotal(800)                      //设置最大连接数,默认值是2
        .setMaxConnPerRoute(400)                   //每个路由最大连接数(一个网址就是一个连接)
        .build();
}

HttpGet

public static void main(String[] args) throws Exception {
    HttpGet httpGet = new HttpGet(url);

    long begin = System.currentTimeMillis();
    HttpResponse response = CLIENT.execute(httpGet);
    long gap = System.currentTimeMillis() - begin;

    int statusCode = response.getStatusLine().getStatusCode();
    LOGGER.info("type {}, response code {}, gap {}", type, statusCode, gap);
    //主动终止连接
    httpGet.abort();
}

第二次 ConnectionPoolTimeoutException

这次代码改好之后,随便点了点,貌似不再出问题了
心理窃喜,于是上 jmeterpostman 批量进行测试

这是 jmeter 响应时间图

image.png

这个图的末尾怎么出现了这么离谱的离散点?

于是手动用postman 再次测了测
再次抛出了异常 ConnectionPoolTimeoutException

用前面博主的命令 去机器上执行,TIME_WAIT 数量也一直很小,陷入了僵局

[root@cf6d9e5767eb94c7e857cd35600149344-node3 ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 42
TIME_WAIT 78

解决

中文资料搜了一堆,发现都是抄来抄去,也没有什么干货
于是转英文

这个回答的意思就是说,reponse的 entity 需要被消费,且相关的流需要被关闭,
并且给出了工具类

EntityUtils.consumeQuietly(response.getEntity());

更新我的代码

public static void main(String[] args) throws Exception {
    HttpGet httpGet = new HttpGet(url);

    long begin = System.currentTimeMillis();
    HttpResponse response = CLIENT.execute(httpGet);
    long gap = System.currentTimeMillis() - begin;

    int statusCode = response.getStatusLine().getStatusCode();
    LOGGER.info("type {}, response code {}, gap {}", type, statusCode, gap);
    //主动终止连接
    httpGet.abort();

    //把 reponse 的流  消费一下
    EntityUtils.consumeQuietly(response.getEntity());
}

测试了一下,终于OK了

最后来张 JMeter

50-响应时间图.png

相关文章

网友评论

      本文标题:HttpClient ConnectionPoolTimeout

      本文链接:https://www.haomeiwen.com/subject/xkrkoqtx.html