Search code examples
javaconnection-poolingapache-httpclient-4.xkeep-alive

Apache HttpClient PoolingHttpClientConnectionManager - allocated to maximum


I have set up PoolingHttpClientConnectionManager (with ssl):

  private PoolingHttpClientConnectionManager getConnManager(
      Registry<ConnectionSocketFactory> socketFactoryRegistry) {
    PoolingHttpClientConnectionManager connectionManager =
        new PoolingHttpClientConnectionManager(socketFactoryRegistry);

    connectionManager.setDefaultMaxPerRoute(configProperties.getConnectionPool().getMaxPerRoute());
    connectionManager.setMaxTotal(configProperties.getConnectionPool().getMaxTotal());
    return connectionManager;
  }

with 1000 of connections and I dont understand this log:

[total available: 1000; route allocated: 1000 of 1000; total allocated: 1000 of 1000]

How is that possible that I have 1000 available connections and 1000 (maximum) of allocated ones?

I have also set up own KeepAliveStrategy to 5s. I would believe that every 5 seconds one of the allocated ones should be released.

    .setKeepAliveStrategy((response, context) -> configProperties.getKeepAlive().toMillis())

Also I was not able to find:

[total available: 0; route allocated: 1000 of 1000; total allocated: 1000 of 1000]

so I have no idea how I got full allocated connections.

Good to mention that this httpclient is then passed to HttpComponentsMessageSender and that one to WebServiceTemplate => doing SOAP calls. Also using SSL and load is quite big - around 100 requests per minute

    JAXBElement result = (JAXBElement) webServiceTemplate.marshalSendAndReceive(url, request);
    WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
    webServiceTemplate.setMarshaller(marshaller());
    webServiceTemplate.setUnmarshaller(marshaller());
    webServiceTemplate.setMessageSender(httpComponentsMessageSender);
    webServiceTemplate.setInterceptors(interceptors.toArray(new ClientInterceptor[0]));
    return webServiceTemplate;
    HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
    httpComponentsMessageSender.setHttpClient(httpClient());
    return httpComponentsMessageSender;
    var sslsf = sslConnectionSocketFactory();
    var socketFactoryRegistry =
        RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslsf).build();

    var baseHttpClient =
        HttpClientBuilder.create()
            .setRetryHandler(
                (exception, executionCount, context) -> {
                  if (exception instanceof InterruptedIOException) {
                    // Logic for transforming timeout exceptions to handled exceptions
                  }
                  return false; // Do not retry
                })
            .setDefaultRequestConfig(
                RequestConfig.custom()
                    .setConnectTimeout(
                        (int) configProperties.getTimeoutConfig().getConnect().toMillis())
                    .setSocketTimeout(
                        (int) configProperties.getTimeoutConfig().getSocket().toMillis())
                    .setConnectionRequestTimeout(
                        (int) configProperties.getTimeoutConfig().getRequestConnect().toMillis())
                    .build())
            .setSSLSocketFactory(sslsf)
            .addInterceptorFirst(new RemoveSoapHeadersInterceptor())
            .setConnectionManager(getConnManager(socketFactoryRegistry))
            .setKeepAliveStrategy((response, context) -> configProperties.getKeepAlive().toMillis())
            .setConnectionTimeToLive(configProperties.getTtl().toMinutes(), TimeUnit.MINUTES)
            .build();

So to finalize this, I don't have 1k of active connections, but still I can see that connection pool is allocated to 1k (which is maximum). My understanding is that when there is no available connection, then new one is allocated. And when there is allocated connection unused, it should be closed after 5s (keepAliveStrategy). But seems like this is not happening and I have allocated to maximum all the time which is taking resources :(

Tried to set up KeepAliveStrategy which did not help. I still see that I have all connections available, but also allocated to maximum


Solution

  • @ok2c was totally right! Adding active evict strategy was kinda hack, but the real issue is that connections are not being reused!

    After much more reading, it turns out SSL connections are stateful and therefore not reused.

    There are two ways to fix it. For us it was easy, just disable state for connections (not secure if you dont know what you are doing)

    .disableConnectionState()
    

    You can find more about it in apache documentation or on stackoverflow