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

Nul*_*ion 3 java spring resttemplate apache-httpclient-4.x

在应用程序没有任何负载的情况下,我在生产过程中突然收到此错误.

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

这是我如何初始化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);
}
Run Code Online (Sandbox Code Playgroud)

致电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)
}
Run Code Online (Sandbox Code Playgroud)

异常堆栈跟踪

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$1.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)
Run Code Online (Sandbox Code Playgroud)

oot*_*ero 9

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

...
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
...
Run Code Online (Sandbox Code Playgroud)

application.yml

httpConnPool:
  maxTotal: 20
  defaultMaxPerRoute: 20
  maxPerRoutes:
    -
      scheme: http
      host: localhost
      port: 8800
      maxPerRoute: 20
Run Code Online (Sandbox Code Playgroud)

我最近在博客上讨论了Spring的RestTemplate请求超时问题,其中使用JMeter和shell命令对请求超时进行了故障排除,并通过配置设置进行了修复.


Bor*_*hov 7

引起:org.apache.http.conn.ConnectionPoolTimeoutException:超时等待池连接

此错误是自我描述.你需要增加生产连接池-目前执行的HttpComponentsClientHttpRequestFactory默认构造函数使用HttpClientBuilder.useSystemProperties().

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

new RestTemplate(new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create()
                    .setMaxConnTotal(200)
                    .setMaxConnPerRoute(50)
                    .build()));
Run Code Online (Sandbox Code Playgroud)

  • 需要考虑的一件事是,如果你没有设置.setMaxConnPerRoute(),我认为默认为4,它对于同一个主机只会使用4个连接,即使它有多大也没关系你可能有另外196个空闲连接,我想是为了防止主机劫持池. (4认同)