Spring Boot 3.4 集成阿里云 PAI-EAS 出现连接池耗尽问题的排查与修复
2026/8/2 13:56:06 网站建设 项目流程

Spring Boot 3.4 集成阿里云 PAI-EAS 出现连接池耗尽问题的排查与修复

昨天凌晨两点,监控平台突然告警,生产环境的 AI 推理服务响应时间从正常的 200ms 飙升到 5000ms,随后大量请求直接超时。查看应用日志,满屏都是org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool。这个异常非常典型,通常意味着 HTTP 连接池被占满且无法释放。当时项目正在对接阿里云 PAI-EAS 模型在线服务,业务量激增触发了这个隐藏极深的资源泄漏问题。

这个问题之所以难排查,是因为它在低并发测试环境下完全不会复现。只有当 QPS 超过一定阈值,且部分请求因网络波动或模型推理耗时较长时,连接池才会迅速枯竭。官方文档虽然推荐直接使用RestTemplateWebClient的默认配置,但在我们这种高并发、长连接的 AI 推理场景下,默认配置反而成了性能瓶颈。

环境准备

本次排查基于生产环境实际配置,确保读者可以复现同样的问题场景。

  • JDK 版本: 21.0.2 LTS
  • Spring Boot 版本: 3.4.0
  • HTTP 客户端: Apache HttpClient 5.3.1 (Spring Boot 3.4 默认不再包含,需显式引入)
  • 阿里云 SDK: alibabacloud-pai-eas 2.0.1
  • 操作系统: Linux Kernel 5.15.0

pom.xml中,除了常规的 Spring Boot Starter 外,必须显式引入 HttpClient 5 的依赖,否则 Spring Boot 3.4 可能会回退到旧版客户端或导致类加载冲突。

```xml

org.springframework.boot
spring-boot-starter-web


org.apache.httpcomponents.client5
httpclient5
5.3.1

```

核心步骤

1. 复现连接池耗尽场景

为了定位问题,首先需要在本地模拟高并发请求。使用 JMH 或简单的线程池模拟 200 个并发线程同时调用 PAI-EAS 的推理接口。默认情况下,Spring Boot 创建的RestTemplate使用的是SimpleClientHttpRequestFactory,它每次请求都会新建连接,或者使用连接池配置极小的HttpComponentsClientHttpRequestFactory

在 200 并发下,默认连接池上限通常为 20,总连接数上限为 200。一旦有部分请求处理时间超过 5 秒,新请求就会因为拿不到连接而抛出ConnectionPoolTimeoutException

2. 分析根因:生命周期不匹配

排查过程中发现,问题不仅仅在于连接数配置。更深层的原因是PoolingHttpClientConnectionManager的生命周期管理不当。很多开发者习惯在@Bean方法中直接 new 一个连接管理器,但这会导致连接池无法优雅关闭,且无法动态调整路由参数。

另一个被忽视的细节是 PAI-EAS 服务的 Keep-Alive 策略。模型推理服务通常倾向于保持长连接以减少握手开销,但如果后端客户端不主动回收空闲连接,空闲连接会一直占用池资源,直到超时。

3. 实施修复方案

修复的核心在于显式配置PoolingHttpClientConnectionManager,并设置合理的MaxConnTotalMaxConnPerRoute。同时,必须开启连接回收机制,定期清理空闲连接。

```java
@Configuration
public class HttpClientConfig {

@Bean
public PoolingHttpClientConnectionManager connectionManager() {
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
// 全局最大连接数,根据业务 QPS 和平均响应时间计算
manager.setMaxTotal(500);
// 单路由最大连接数,PAI-EAS 通常只有一个 endpoint
manager.setDefaultMaxPerRoute(200);
return manager;
}

@Bean
public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager manager) {
return HttpClientBuilder.create()
.setConnectionManager(manager)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(5, TimeUnit.SECONDS)
.setConnectionRequestTimeout(5, TimeUnit.SECONDS)
.setSocketTimeout(60, TimeUnit.SECONDS)
.build())
.build();
}

@Bean
public RestTemplate restTemplate(CloseableHttpClient httpClient) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setReadTimeout(60000);
return new RestTemplate(factory);
}
}
```

此外,必须引入连接回收线程。这是官方文档中容易遗漏的部分。如果不启动回收线程,连接池中的空闲连接不会自动释放,导致高并发后连接数居高不下。

```java
@PostConstruct
public void init() {
// 每 30 秒回收一次空闲连接
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
connectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
connectionManager.closeExpiredConnections();
}
}, 30000, 30000);
}
```

验证与常见问题

修复完成后,再次进行 500 并发压测。观察JVM的线程状态和网络连接数,连接池不再出现Timeout异常。平均响应时间稳定在 300ms 以内,P99 延迟控制在 1.2s 左右。

| 配置项 | 默认配置表现 | 优化后配置表现 | 说明 |
| :--- | :--- | :--- | :--- |
| 最大连接数 (MaxTotal) | 20 | 500 | 默认值过小,无法支撑高并发 |
| 单路由连接数 (MaxPerRoute) | 20 | 200 | 针对单一 AI 服务端点需调大 |
| 连接超时时间 (ConnectTimeout) | 默认 5s | 5s | 保持短超时,快速失败 |
| 空闲连接回收 | 无 | 每 30s 回收 | 防止连接泄漏和僵尸连接 |

常见问题中,还有一个容易被忽略的点:HttpClient实例必须是单例的。如果在每个 Controller 方法中都 new 一个HttpClient,会导致线程数爆炸和端口耗尽。务必确保CloseableHttpClient作为 Spring Bean 被管理。

另外,有开发者尝试通过增加MaxConnTotal到 10000 来解决超时,这个方案虽然官方推荐,但在我们场景下反而更糟。过大的连接数会导致 TCP 握手风暴,触发阿里云端限流,最终导致整体服务不可用。合理的数值应该基于QPS * 平均响应时间来估算。

总结

对接阿里云 PAI-EAS 这类 AI 推理服务时,不能简单套用 Web 服务的 HTTP 配置。模型推理的耗时特性要求客户端具备更稳健的连接管理能力。显式配置连接池、启用空闲连接回收、确保 HttpClient 单例化,是避免生产环境连接池耗尽的三道防线。默认配置往往是为了通用场景设计的,在高并发垂直场景下,必须根据实际业务指标进行调优。

#后端 #Java #SpringBoot #阿里云 #HttpClient


你在实际项目中有遇到类似问题吗?欢迎在评论区分享你的经验和解决方案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询