You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache HttpClient 5.2连接池超时异常问题咨询

问题

我们正从Apache HttpClient 4.5升级至5.2版本,发现连接池超时机制发生重大变化。我们希望配置固定数量的可用连接,额外线程无需等待。由于非正值会被视为无限超时,因此将ConnectionRequestTimeout设置为1ms,以便连接池耗尽时立即检测并失败。

在4.5版本中该方案运行正常,但在5.2版本中,超时检查似乎提前触发,即使连接池仍有可用连接也会报错。以下是可稳定复现问题的测试代码:

class Test {

    static CloseableHttpClient client;

    public static void main(String[] args) {
        var requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(Timeout.ofMilliseconds(1))
                .build();

        var connManager = new PoolingHttpClientConnectionManager();
        connManager.setMaxTotal(50);
        connManager.setDefaultMaxPerRoute(50);

        client = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connManager)
                .build();

        for (int i = 0; i < 45; i++) {
            new Requester().start();
        }
    }

    static class Requester extends Thread {
        String result;

        @Override
        public void run() {
            try {
                result = client.execute(new HttpGet("https://www.example.com"), ClassicHttpResponse::toString);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

运行后会输出如下堆栈信息:

org.apache.hc.client5.http.impl.classic.RequestFailedException: Request execution failed
    at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.acquireEndpoint(InternalExecRuntime.java:131)
    at org.apache.hc.client5.http.impl.classic.ConnectExec.execute(ConnectExec.java:125)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.ProtocolExec.execute(ProtocolExec.java:192)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.HttpRequestRetryExec.execute(HttpRequestRetryExec.java:113)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.ContentCompressionExec.execute(ContentCompressionExec.java:152)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.RedirectExec.execute(RedirectExec.java:116)
    at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
    at org.apache.hc.client5.http.impl.classic.InternalHttpClient.doExecute(InternalHttpClient.java:170)
    at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:245)
    at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:188)
    at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:162)
    at Test$Requester.run(Test.java:40)
Caused by: org.apache.hc.core5.util.DeadlineTimeoutException: Deadline: 2024-01-10T02:02:37.621+0000, -15 MILLISECONDS overdue
    at org.apache.hc.core5.util.DeadlineTimeoutException.from(DeadlineTimeoutException.java:49)
    at org.apache.hc.core5.pool.StrictConnPool.lease(StrictConnPool.java:222)
    at org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager.lease(PoolingHttpClientConnectionManager.java:298)
    at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.acquireEndpoint(InternalExecRuntime.java:103)
    ... 15 more

将超时时间增加至25ms可降低超时频率,但仍会偶尔出现问题。请问这是bug吗?是否有其他方式配置低超时或无超时的连接池?

回答

这不是Bug,是HttpClient 5.x的设计变更

HttpClient 5.x对连接池的超时计算逻辑做了调整:在4.x中,ConnectionRequestTimeout是线程等待连接的最长时间;但在5.x中,这个超时是从请求开始到获取到连接的总时间窗口,包括请求调度、池内锁竞争、连接创建(如果需要)等所有前置耗时。即使池内有空闲连接,线程调度、锁获取的微小延迟也可能耗尽1ms的超时窗口,触发超时异常。

替代方案

若要实现「连接池耗尽时立即失败,不等待」的需求,可通过以下方式配置:

  1. 利用5.x的超时语义直接配置
    在HttpClient 5.x中,Timeout.ofMilliseconds(0)代表「立即超时,不等待」,而非无限等待(无限等待为Timeout.ofMilliseconds(-1))。只需将ConnectionRequestTimeout设置为0ms,配合已配置的最大连接数限制,就能实现连接池耗尽时直接拒绝请求的效果。修改后的请求配置代码:

    var requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(Timeout.ofMilliseconds(0))
            .build();
    
  2. 确认连接池策略
    HttpClient 5.x默认使用StrictConnPool,当池内无空闲连接且已达最大限制时,会直接触发超时(若设置了0ms超时则立即失败),无需额外调整连接池策略。

额外说明

  • 避免设置极小的超时值(如1ms),正常的线程调度和锁操作都可能超过这个时间,导致误判。
  • 明确5.x中Timeout类的语义:
    • Timeout.ofMilliseconds(-1):无限等待
    • Timeout.ofMilliseconds(0):立即超时,不等待
    • 正数:实际等待时间窗口

内容的提问来源于stack exchange,提问作者shmosel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:14:50