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

Spring Boot 1.5.4微服务RestTemplate多API调用负载下响应延迟问题

解决Spring Boot 1.5.4微服务负载下REST接口响应延迟问题

嘿,我来帮你捋捋这个问题!根据你描述的情况——负载场景下调用两个微服务的GET接口响应时间持续增加,且日志显示第一个API调用完成后没立刻执行第二个、反而陷入等待——大概率是RestTemplate连接池配置不到位或者同步调用导致的线程阻塞在拖后腿,下面具体拆解问题并给出可行的解决方案:

一、先检查RestTemplate的连接池配置

Spring Boot 1.5.x默认的RestTemplate是没有启用连接池的,每次请求都会新建HTTP连接。在高负载下,连接创建的开销会被无限放大,甚至可能出现连接耗尽,导致线程被迫等待新连接可用,这完全符合你看到的“完成第一个调用后等待”的现象。

  • 如果你还没给RestTemplate配置连接池,赶紧安排上!这里给你一个Apache HttpClient的配置示例,直接抄就能用:
    @Bean
    public RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        // 设置连接超时(毫秒)
        factory.setConnectTimeout(5000);
        // 设置读取超时(毫秒)
        factory.setReadTimeout(5000);
        
        // 配置连接池核心参数
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        // 服务器允许的最大总连接数
        connectionManager.setMaxTotal(200);
        // 每个目标服务的最大连接数
        connectionManager.setDefaultMaxPerRoute(50);
        
        CloseableHttpClient httpClient = HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .build();
        factory.setHttpClient(httpClient);
        
        return new RestTemplate(factory);
    }
    
    注意setMaxTotal和defaultMaxPerRoute的数值要根据你的实际负载调整,别太小导致连接不够用,也别太大浪费资源。

二、把同步调用改成异步并行调用

你现在应该是先同步调用第一个微服务,等它返回后再调用第二个——这种串行逻辑在低负载下没问题,但高负载时会把大量Tomcat工作线程卡在等待响应上,线程耗尽后后续请求只能排队,响应时间自然越来越长。

解决这个问题的核心是让两个微服务的请求并行执行,这里给你两种方案:

方案1:用AsyncRestTemplate实现异步调用(Spring Boot 1.5.x原生支持)

@Autowired
private AsyncRestTemplate asyncRestTemplate;

public ResponseEntity<ResponseDTO> getCombinedResponse() {
    // 同时发起两个异步请求
    ListenableFuture<ResponseEntity<Service1DTO>> future1 = asyncRestTemplate.getForEntity("http://service1/api", Service1DTO.class);
    ListenableFuture<ResponseEntity<Service2DTO>> future2 = asyncRestTemplate.getForEntity("http://service2/api", Service2DTO.class);

    // 等待两个请求都完成(设置超时时间避免无限等待)
    try {
        ResponseEntity<Service1DTO> resp1 = future1.get(5, TimeUnit.SECONDS);
        ResponseEntity<Service2DTO> resp2 = future2.get(5, TimeUnit.SECONDS);
        // 合并两个接口的返回结果
        return ResponseEntity.ok(combineResponses(resp1.getBody(), resp2.getBody()));
    } catch (Exception e) {
        // 处理超时或异常情况
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

别忘了给AsyncRestTemplate也配置连接池,不然异步调用的优势会大打折扣。

方案2:自定义线程池实现并行调用

如果不想用AsyncRestTemplate,也可以自己用线程池来并行执行两个请求:

@Autowired
private RestTemplate restTemplate;

@Autowired
private ExecutorService taskExecutor;

public ResponseEntity<ResponseDTO> getCombinedResponse() {
    // 封装两个请求为Callable任务
    Callable<Service1DTO> task1 = () -> restTemplate.getForObject("http://service1/api", Service1DTO.class);
    Callable<Service2DTO> task2 = () -> restTemplate.getForObject("http://service2/api", Service2DTO.class);

    // 提交任务并等待完成(设置超时)
    List<Future<?>> futures = taskExecutor.invokeAll(Arrays.asList(task1, task2), 5, TimeUnit.SECONDS);
    
    try {
        Service1DTO resp1 = (Service1DTO) futures.get(0).get();
        Service2DTO resp2 = (Service2DTO) futures.get(1).get();
        return ResponseEntity.ok(combineResponses(resp1, resp2));
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

然后在配置类里定义线程池:

@Bean
public ExecutorService taskExecutor() {
    // 线程数根据你的负载调整,比如10-20之间
    return Executors.newFixedThreadPool(10);
}

三、其他辅助排查点

  • 调整Tomcat线程池:Spring Boot 1.5.x默认Tomcat最大线程数是200,高负载下如果线程被长时间阻塞,会导致请求排队。可以在application.properties里修改:
    server.tomcat.max-threads=400
    server.tomcat.accept-count=100
    
  • 导出线程栈分析:用jstack命令导出服务的线程栈,看看是不是有大量线程处于WAITING或BLOCKED状态,精准定位阻塞点。
  • 检查服务注册发现状态:如果用了Eureka这类组件,确认服务实例的健康检查是否正常,有没有出现实例不健康但还在接收请求的情况,或者负载均衡策略是否合理导致请求集中在少数实例上。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:52:41