java RestTemplate + ConnectionPoolTimeoutException:等待来自池的连接超时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31597696/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 18:50:40  来源:igfitidea点击:

RestTemplate + ConnectionPoolTimeoutException: Timeout waiting for connection from pool

javaspringapache-httpclient-4.xresttemplate

提问by NullPointerException

I got this error all of a sudden in production while the application was not under any load.

当应用程序没有任何负载时,我在生产中突然出现此错误。

The issue happened when my code tries to send the PUT message using spring rest template

当我的代码尝试使用 spring rest 模板发送 PUT 消息时发生了问题

Here is the code how I am initialing the restTemplate

这是我如何初始化 restTemplate 的代码

private static final RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
{

    List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setClassesToBeBound(PaymentSession.class);
    MarshallingHttpMessageConverter marshallingHttpMessageConverter = new MarshallingHttpMessageConverter(marshaller, marshaller);
    marshallingHttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_XML, MediaType.TEXT_HTML));
    messageConverters.add(marshallingHttpMessageConverter);
    restTemplate.setMessageConverters(messageConverters);
}

Call to PUT

调用 PUT

try {
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_XML);
    HttpEntity<PaymentSession> httpEntity = new HttpEntity<PaymentSession>(session, headers);

    restTemplate.exchange(baseUrl+"/v1/psps", HttpMethod.PUT, httpEntity, PaymentSession.class);

}catch(HttpClientErrorException e){
        logger.error("Exception..!!",e)
}

Exception stacktrace

异常堆栈跟踪

Caused by: org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
at org.apache.http.impl.conn.PoolingClientConnectionManager.leaseConnection(PoolingClientConnectionManager.java:232)
at org.apache.http.impl.conn.PoolingClientConnectionManager.getConnection(PoolingClientConnectionManager.java:199)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:456)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:88)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:49)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:509)

回答by ootero

I would suggest to configure HttpComponentsClientHttpRequestFactoryinstance being passed in the constructor of RestTemplateincreasing defaultMaxPerRouteor maxPerRoutefor the specific http route for which requests are timing out, increasing the pool size is not enough, as I mentioned in a comment, even if you set PoolingHttpClientConnectionManager.setMaxTotal()to 200, HttpComponentsClientHttpRequestFactoryuses a defaultMaxPerRouteof 4, my guess would be in an attempt for a host route (scheme, host, port) not to hiHyman the connection pool)

我建议配置HttpComponentsClientHttpRequestFactoryRestTemplate增加的构造函数中传递的实例defaultMaxPerRoutemaxPerRoute对于请求超时的特定 http 路由,增加池大小是不够的,正如我在评论中提到的,即使您设置PoolingHttpClientConnectionManager.setMaxTotal()为 200,也HttpComponentsClientHttpRequestFactory使用defaultMaxPerRoute共 4 个,我的猜测是尝试使主机路由(方案、主机、端口)不劫持连接池)

...
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
        PoolingHttpClientConnectionManager result = new PoolingHttpClientConnectionManager();
        result.setMaxTotal(this.httpHostConfiguration.getMaxTotal());
        // Default max per route is used in case it's not set for a specific route
        result.setDefaultMaxPerRoute(this.httpHostConfiguration.getDefaultMaxPerRoute());
        // and / or
        if (CollectionUtils.isNotEmpty(this.httpHostConfiguration.getMaxPerRoutes())) {
            for (HttpHostConfiguration httpHostConfig : this.httpHostConfiguration.getMaxPerRoutes()) {
                HttpHost host = new HttpHost(httpHostConfig.getHost(), httpHostConfig.getPort(), httpHostConfig.getScheme());
                // Max per route for a specific host route
                result.setMaxPerRoute(new HttpRoute(host), httpHostConfig.getMaxPerRoute());
            }
        }
        return result;
    }
  ...


@Configuration
@ConfigurationProperties(prefix = "httpConnPool")
public class HttpHostsConfiguration {

  private Integer maxTotal;
  private Integer defaultMaxPerRoute;
  private List<HttpHostConfiguration> maxPerRoutes;

  // Getters, Setters
...

application.yml

应用程序.yml

httpConnPool:
  maxTotal: 20
  defaultMaxPerRoute: 20
  maxPerRoutes:
    -
      scheme: http
      host: localhost
      port: 8800
      maxPerRoute: 20

I recently blog about Troubleshooting Spring's RestTemplate Requests Timeoutwhere requests timing out were troubleshooted using JMeterand shell commands and fixed via configuration settings.

我最近写了一篇关于Spring 的 RestTemplate 请求超时故障排除的博客,其中请求超时使用JMetershell 命令进行故障排除并通过配置设置修复。

回答by Boris Treukhov

Caused by: org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool

引起:org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool

This error is self describing. You need to increase your connection pool in production - current implementation of HttpComponentsClientHttpRequestFactorydefault constructor is using HttpClientBuilderwith .useSystemProperties().

这个错误是自我描述的。您需要在生产中增加连接池 -HttpComponentsClientHttpRequestFactory默认构造函数的当前实现使用HttpClientBuilderwith .useSystemProperties()

I believe it will be 5 connections by default. This works for client but is unlikely what you want in server environment. You need to use something like

我相信默认情况下它将是 5 个连接。这适用于客户端,但在服务器环境中不太可能是您想要的。你需要使用类似的东西

new RestTemplate(new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create()
                    .setMaxConnTotal(200)
                    .setMaxConnPerRoute(50)
                    .build()));

回答by cwa

The problem is the HTTP client connections aren't being closed. I had the same problem with a service that only has about 1 request per second.

问题是 HTTP 客户端连接没有被关闭。我对每秒只有大约 1 个请求的服务遇到了同样的问题。

"exception":"org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool"

You need to add a finally block and close the connection.

您需要添加一个 finally 块并关闭连接。