ConnectionPoolTimeoutException: Timeout waiting for connection from pool的错误排查及解决

ConnectionPoolTimeoutException: Timeout waiting for connection from pool的错误排查及解决


昨天遇到一个特别奇怪的事情,在系统中本来有个外部接口的方法,运行了好几年,一直正常,突然昨天开始出现异常,并且异常也比较奇怪,排查了好长时间。先看下原始代码:

    static {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setConnectionRequestTimeout(2000)
                .setSocketTimeout(5000).build();
        defaultHttpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)
                .setMaxConnTotal(200)
                .setMaxConnPerRoute(100)
                .build();
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                defaultHttpClient.close();
            } catch (IOException ignored) {
            }
        }));
    }
    public static String httpGet(String url) {
        //先创建一个HttpGet对象,传入目标的网络地址,然后调用HttpClient的execute()方法即可:
        HttpGet httpGet = new HttpGet();
        httpGet.setURI(URI.create(url));
        HttpResponse response = null;
        String resp = "";
        try {
            response = defaultHttpClient.execute(httpGet);
            // 取响应的结果
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_OK) {
                resp = EntityUtils.toString(response.getEntity(), "utf-8");
            }
        } catch (IOException e) {
            logger.error("httpGet error:", e);
        }
        return resp;
    }

代码很简单,但是在调用httpGet这个方法的时候,调用一段时间,就出现这个问题。开始以为是并发量太大,但是看流量也没有很大的并发,我们模拟了100个并发,也没有问题,一时不知道怎么排查。然后我们再响应码加了debug日志,生产环境又运行了一段时间,又开始报错,导致客户端接口调用直接失败。我们再仔细观察日志,发现响应码statusCode 有很多500,我们就考虑是不是因为这个的原因呢。
我们查看了这段时间statusCode =500的请求数量,恰好是等于100,而我们出现异常的情况正好是statusCode =500的第100条之后发生的,至此我们明白了,是因为在statusCode =500代码没有做任何处理,导致连接没有释放给连接池。而statusCode == HttpStatus.SC_OK,我们进行了response.getEntity(),这源码中是有关闭连接的方法的。所以我们做了以下修改:

    public static String httpGet(String url) {
        //先创建一个HttpGet对象,传入目标的网络地址,然后调用HttpClient的execute()方法即可:
        HttpGet httpGet = new HttpGet();
        httpGet.setURI(URI.create(url));
        HttpResponse response = null;
        String resp = "";
        try {
            response = defaultHttpClient.execute(httpGet);
            // 取响应的结果
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_OK) {
                resp = EntityUtils.toString(response.getEntity(), "utf-8");
            } else {
                httpGet.releaseConnection();
            }
        } catch (Exception e) {
            httpGet.releaseConnection();
            logger.error("httpGet error:", e);
        } finally {
            httpGet.abort();
        }
        return resp;
    }

然后模拟了200次的500的请求,系统依然正常,没有再报错。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值