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

时间:2015-07-23 20:44:23

标签: java spring apache-httpclient-4.x resttemplate

我在生产过程中突然出现了这个错误,而应用程序没有任何负载。

当我的代码尝试使用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);
}

致电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)
}

异常堆栈跟踪

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)

3 个答案:

答案 0 :(得分:7)

  

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

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

我相信默认情况下会有5个连接。这适用于客户端,但在服务器环境中不太可能。 你需要使用像

这样的东西
new RestTemplate(new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create()
                    .setMaxConnTotal(200)
                    .setMaxConnPerRoute(50)
                    .build()));

答案 1 :(得分:7)

我建议配置Workbooks.Open Filename:="Workbook_FullName.xltm", Editable:=True 实例在HttpComponentsClientHttpRequestFactory增加RestTemplatedefaultMaxPerRoute的构造函数中为请求超时的特定http路由传递,增加正如我在评论中提到的那样,游泳池大小还不够,即使您将maxPerRoute设置为200,PoolingHttpClientConnectionManager.setMaxTotal()使用的HttpComponentsClientHttpRequestFactory为4,我的猜测也是为了尝试主机路由(方案,主机,端口)不要劫持连接池)

defaultMaxPerRoute

<强> application.yml

...
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
...

我最近发表了关于Troubleshooting Spring's RestTemplate Requests Timeout的博客,其中使用httpConnPool: maxTotal: 20 defaultMaxPerRoute: 20 maxPerRoutes: - scheme: http host: localhost port: 8800 maxPerRoute: 20 和shell命令并通过配置设置修复了请求超时的问题。

答案 2 :(得分:0)

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

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

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