【问题标题】:Why RestTemplate hangs when called concurrently?为什么 RestTemplate 在同时调用时会挂起?
【发布时间】:2018-07-29 09:23:11
【问题描述】:

我有一个基于 Spring Boot 的应用程序并使用 RestTemplate 发送 HTTP 请求。应用程序向其发送请求的一些端点响应非常慢,但有些应该快速响应。当使用 RestTemplate 的服务被大约 20 个线程并行使用时,RestTemplate 碰巧挂起并等待某些东西(一些对快速端点的请求的执行速度比它们应该执行的慢得多)。 当我切换到 Jersey HTTP 客户端时,问题就消失了,所以它一定是 RestTemplate 本身的问题。

我用RestTemplateBuilder创建bean:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

并使用exchange方法发送请求:

ResponseEntity<Void> result = restTemplate.exchange(url, HttpMethod.POST, request, Void.class);

有谁知道为什么 RestTemplate 会有这样的行为?

【问题讨论】:

标签: java spring rest resttemplate


【解决方案1】:

如果你在 spring boot 项目中有执行器依赖,它在内部使用 Micrometer 来生成指标。

其中一个指标是 http.client.requests,它跟踪 RestTemplate 处理的所有请求。在内部,千分尺创建了一个 ConcurrentHashMap,它跟踪每个端点作为键。例如 - 如果你有一个端点说

/api/user/{userId}

如果你用不同的用户 ID 击中它 100 次,千分尺将在其地图中创建 100 个条目。对于较低的环境,这不是问题。但在 PROD 环境中可能会导致性能显着下降,在此环境中可能会堆积数千个条目,并在 Major GC 启动之前减慢响应时间。

一种解决方案是通过在 application.properties 中包含以下属性来关闭此指标

management.metrics.enable.http.client.requests=false

【讨论】:

    【解决方案2】:

    可能与RestTemplate配置设置有关。

    你可以运行netstat -an | grep &lt;app port&gt;(例如8800)来寻找类似的东西:

    ...
    lot of:
    TCP 127.0.0.1:61186 127.0.0.1:8800 TIME_WAIT
    TCP 127.0.0.1:61190 127.0.0.1:8800 TIME_WAIT
    
    
    handful of:
    TCP 127.0.0.1:61198 127.0.0.1:8800 ESTABLISHED
    TCP 127.0.0.1:61204 127.0.0.1:8800 ESTABLISHED
    ...
    

    即使 RestTemplate 可能已针对多个连接进行了配置,RestTemplate 的 maxPerRoutes 仍可防止主机(响应时间较长)劫持连接池。

    您可能需要一个以上的 RestTemplate 实例,转到 async,修复/改进依赖端点的响应时间,...

    前段时间我写了一篇关于这个问题的博客:Troubleshooting Spring's RestTemplate Requests Timeout

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多