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

Spring RestTemplate调用外部REST接口偶现Connection reset问题求解

问题排查与修复方案

根本原因

该偶发的Connection reset异常是典型的连接池内的空闲连接被服务端提前断开,客户端未感知到连接失效,继续复用过期连接导致的问题:

  • 当前使用的Apache HttpClient连接池默认未启用空闲连接检测、未设置连接最大存活时间
  • 第三方接口服务端通常会设置TCP连接的keepalive超时时间,多为30s/60s,超过该时长无流量就会主动断开连接,此时客户端连接池内的对应连接已经失效,但客户端未做有效性校验就直接复用发送请求,就会触发连接重置异常
  • 异常后数分钟自动恢复是因为连接池内的失效连接被耗尽后,客户端会主动新建连接,流量就会自动恢复正常

排查步骤

  • 确认第三方服务端的TCP keepalive超时时间、HTTP连接最大存活时间,拿到服务端主动断开连接的阈值
  • 开启Apache HttpClient的调试日志,统计异常出现前对应连接的空闲时长,确认是否超过服务端的keepalive阈值
  • 监控连接池的活跃连接、空闲连接数量变化,确认异常发生时是否有大量空闲连接被复用

修复方案

1. 配置连接池空闲连接驱逐策略、连接最大存活时间

修改PoolingHttpClientConnectionManager的Bean配置,增加最大连接存活时间,配置定时驱逐空闲连接:

@Bean
@Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT)
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager()
{
    log.info("PoolingHttpClientConnectionManager Build for {}", ConfigConstants.CONFIG_NAME_DEFAULT);
    // 设置连接最大存活时间,这里设为30s,建议比服务端的keepalive超时小10%左右
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
    poolingHttpClientConnectionManager.setMaxTotal(maxTotalConnections);
    poolingHttpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
    // 开启空闲连接驱逐,每5秒执行一次,清理空闲超过20秒的连接
    poolingHttpClientConnectionManager.closeIdleConnections(20, TimeUnit.SECONDS);
    poolingHttpClientConnectionManager.setValidateAfterInactivity(5000);
    return poolingHttpClientConnectionManager;
}

2. 配置HttpClient的重试策略

在构建CloseableHttpClient的时候增加幂等请求重试配置,遇到连接重置异常时自动重试:

@Bean(destroyMethod = "close")
@Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT)
public CloseableHttpClient closeableHttpClient(
        @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT) PoolingHttpClientConnectionManager poolingHttpClientConnectionManager
) {
    log.info("CloseableHttpClient Build for {}", ConfigConstants.CONFIG_NAME_DEFAULT);
    // 配置重试策略,连接异常最多重试2次
    HttpRequestRetryHandler retryHandler = (exception, executionCount, context) -> {
        if (executionCount > 2) {
            return false;
        }
        // 连接重置、连接超时这类连接异常可重试
        if (exception instanceof SocketException || exception instanceof ConnectTimeoutException) {
            return true;
        }
        return false;
    };
    return HttpClientBuilder.create()
            .setConnectionManager(poolingHttpClientConnectionManager)
            .setRetryHandler(retryHandler)
            .build();
}

3. 配置请求层面的连接校验

在HttpComponentsClientHttpRequestFactory中开启连接校验,复用连接前先确认连接是否有效:

requestFactory.setValidateAfterInactivity(5000);

4. 可选方案:禁用HTTP连接复用

如果业务请求量不大,也可以直接禁用连接复用,每次请求新建连接,就不会出现复用失效连接的问题,缺点是请求性能会有一定损耗:

return HttpClientBuilder.create()
        .setConnectionManager(poolingHttpClientConnectionManager)
        .setConnectionReuseStrategy((response, context) -> false)
        .build();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:24:08