You are viewing a plain text version of this content. The canonical link for it is here.
Posted to httpclient-users@hc.apache.org by Pete Keyes <PK...@starbucks.com> on 2016/02/23 02:11:17 UTC

pooling connection manager: changing max per route

version: 4.4.1
App Server: TomEE7

We use PoolingHttpClientConnectionManager with the following defaults:

  *   max total connections: 100,000
  *   default max per route: 50

we create the HttpClient and PoolingHttpClientConnectionManager as static singletons at container startup.
private static Thread globalConnManagerThread;
private static CloseableHttpClient globalHttpClient;
static {
        // create global pooling connection manager
        globalConnManagerPool = new PoolingHttpClientConnectionManager(
            registry
        );
        globalConnManagerPool.setDefaultMaxPerRoute(50);
        globalConnManagerPool.setMaxTotal(100000);

        // create global HttpClient instance
        final HttpClientBuilder builder = HttpClients.custom()
            .setConnectionManager(globalConnManagerPool)
            .setConnectionManagerShared(true)
            .setConnectionTimeToLive(5, TimeUnit.MINUTES)
            .setDefaultConnectionConfig(connConfig)
            .setDefaultRequestConfig(requestConfig)
            .setMaxConnPerRoute(50)  // <<== default per route is 50
            .setDefaultSocketConfig(socketConfig)
            .setMaxConnTotal(100000)
            .setRetryHandler(httpRetryHandler)
            .useSystemProperties()
        ;
        CloseableHttpClient globalHttpClient = builder.build();
}

We set the max per specific route with the following code snippet:

@PostConstruct public void init() {
    List<URL> allUrls = getAllUrls();
    for(final URL url : allUrls) {
        HttpServiceConfig hsc = getHttpServiceConfig(url);

        final String host = url.getHost();
        final int portNo = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
        final String protocol = url.getProtocol();
        final HttpHost httpHost = new HttpHost(host, portNo, protocol);
        final HttpRoute httpRoute = new HttpRoute(httpHost);
        globalConnManagerPool.setMaxPerRoute(httpRoute, 200);  // <<== max set to 200 for route
        log.info(gMarker, "set route max-conns:"
            + "; max-allowed=" + hsc.getMaxConns()
            + "; protocol-host-port=" + protocol + "://" + host + ":" + portNo
            + "; httpRoute=" + String.valueOf(httpRoute)
        );
    }
}


we see each route specific max connection log message at startup.  for instance:
set route max-conns: conns-max=200; protocol-host-port=https://some-host:443; httpRoute={}->https://some-host:443

we have a background thread that monitors the apache-hc connection pool statistics and emits log messages.  we see the following apache-hc connection manager pool “route specific” statistics logged:
private void logPoolStats() {
    Set<HttpRoute> routes = globalConnManagerPool.getRoutes();
    for(final HttpRoute r : routes) {
        final PoolStats ps = cm.getStats(r);
        final int available = ps.getAvailable();
        final int active = ps.getLeased();
        final int limit = ps.getMax();
        final int blocking = ps.getPending();

        String s = "emit statistic:"
            + " type=hc-conn-pool"
            + "; route=" + hostname
            + "; available=" + available
            + "; active=" + active
            + "; blocking=" + blocking
            + "; max-allowed=" + limit
            + "; server-nm=" + Helpers.getLocalHost() + ":" + Helpers.getServerHttpsPort()
        ;
        log.info(marker, s);
    }
}

we see log messages like the following from the apache-hc connection pool monitor logging:
emit statistic: type=hc-conn-pool; route=some-host; available=1; active=0; blocking=0; max-allowed=50

The connection manager isn’t respecting the per-route connection settings.  Above we see that the “max-allowed” per route reported by the pool-manager is 50 for a route that specifically set the max-allowed to 200.

Any hints about what we are doing wrong to override the limit on a per-route basis?

—
Pete Keyes


Re: pooling connection manager: changing max per route

Posted by Pete Keyes <PK...@starbucks.com>.
I can see why the CM pool is reporting different values.  The object in the CM pool returned by CM.getRoutes() ends up with a different HttpRoute.hashCode() than the actual HttpRoute created just prior to invoking the service.

in method to execute service:
    public class HttpClientConnLimitTest {
    // keep reference to original object
    private static HttpRoute theRoute;

    public void run() {
      final URL url = new URL("https://HOSTNAME:PORTNO/GET/SERVICE/URI");
      final String urlText = url.toString();
      final String host = url.getHost();
      final int portNo = url.getPort();
      final String protocol = url.getProtocol();
      final HttpHost httpHost = new HttpHost(host, portNo, protocol);
      final HttpRoute httpRoute = new HttpRoute(httpHost);
      theRoute = httpRoute;
      globalConnManagerPool.setMaxPerRoute(httpRoute, 200);
      ...rest of code the same...
    }

in background thread monitoring pool:
    private void getPoolStats() {
      Set<HttpRoute> routes = cm.getRoutes();
      for(final HttpRoute cmRoute : routes) {
        log("compare this cm-route with the-route:"
            + " cm-route-hash=" + cmRoute.hashCode()
            + "; the-route-hash=" + theRoute.hashCode()
            + "; cm-route-string=" + String.valueOf(cmRoute)
            + "; the-route-string=" + String.valueOf(theRoute)
            + "; equal=" + cmRoute.equals(theRoute)
        );
      }
      ...rest of code the same...
    }

output logged is:
  compare this cm-route with the-route:
    cm-route-hash   =-365947017;
    the-route-hash  =-365948386;
    cm-route-string ={s}->https://lx01796:2443;
    the-route-string={}->https://lx01796:2443;
    equal=false

The HttpRoute objects are different:
    from cmRoute.hashCode() : -365947017
    from theRoute.hashCode(): -365948386
The toString values show why they differ.  The route stored by CM has been marked secure ({s}) while the actual HttpRoute object (theRoute) has not been marked secure ({}).
    from String.valueOf(cmRoute) : {s}->https://lx01796:2443
    from String.valueOf(theRoute): {}->https://lx01796:2443

That is the reason for the issue.  For some reason HttpRoute makes the decision to never check the HttpHost protocol to see if it is secure. Using new HttpRoute(HttpHost) will set “secure” to false every time.
    public HttpRoute(final HttpHost target) {
        this(target, null, Collections.<HttpHost>emptyList(), false,
                TunnelType.PLAIN, LayerType.PLAIN);
    }
Yet, somewhere else down the line the CM correctly recognizes that this is an HTTP/s (secure) route and within the pool it has marked the route as such.  By changing my code to use this other constructor and set “secure” based on the protocol we get correct per-route pool management.
    public HttpRoute(final HttpHost target, final InetAddress local, final boolean secure) {
        this(target, local, Collections.<HttpHost>emptyList(), secure,
                TunnelType.PLAIN, LayerType.PLAIN);
    }

Output after changing the constructor in my example code:
  compare this cm-route with the-route:
    cm-route-hash   =-1772283693;
    the-route-hash  =-1772283693;
    cm-route-string ={s}->https://lx01796:2443;
    the-route-string={s}->https://lx01796:2443;
    equal=true

Why the output from your test and mine differ - remains a mystery.  But, thank god Oleg is very diligent in his toString() overrides.  Without that I’d have never been able to discover any reason for this odd behavior.

Hopefully this was helpful to someone other than just me.

As always - thank you for this brilliant apache project Oleg.

—
Pete


From: "olegk@apache.org<ma...@apache.org>" <ol...@apache.org>>
Reply-To: HttpClient Discussion <ht...@hc.apache.org>>
Date: Thursday, February 25, 2016 at 8:26 AM
To: HttpClient Discussion <ht...@hc.apache.org>>
Subject: Re: pooling connection manager: changing max per route

On Thu, 2016-02-25 at 16:15 +0000, Pete Keyes wrote:
Thank you.  Just to make sure . . . you used apache-hc version 4.4.1 for this test?

I must confess I have used 4.5.2 but I do not recall any issues in the
connection management code since 4.1.

Oleg

—
Pete Keyes
Starbucks Coffee Co.
w: 206-318-5933
c: 206-914-4134
From: "olegk@apache.org<ma...@apache.org>" <ol...@apache.org>>
Reply-To: HttpClient Discussion <ht...@hc.apache.org>>
Date: Thursday, February 25, 2016 at 3:25 AM
To: HttpClient Discussion <ht...@hc.apache.org>>
Subject: Re: pooling connection manager: changing max per route
I ran your code and did not see a single log entry with
'max-allowed=50'.
Oleg



---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org<ma...@hc.apache.org>
For additional commands, e-mail: httpclient-users-help@hc.apache.org<ma...@hc.apache.org>



Re: pooling connection manager: changing max per route

Posted by Oleg Kalnichevski <ol...@apache.org>.
On Thu, 2016-02-25 at 16:15 +0000, Pete Keyes wrote:
> Thank you.  Just to make sure . . . you used apache-hc version 4.4.1 for this test?
> 

I must confess I have used 4.5.2 but I do not recall any issues in the
connection management code since 4.1.

Oleg

> —
> Pete Keyes
> Starbucks Coffee Co.
> w: 206-318-5933
> c: 206-914-4134
> 
> 
> From: "olegk@apache.org<ma...@apache.org>" <ol...@apache.org>>
> Reply-To: HttpClient Discussion <ht...@hc.apache.org>>
> Date: Thursday, February 25, 2016 at 3:25 AM
> To: HttpClient Discussion <ht...@hc.apache.org>>
> Subject: Re: pooling connection manager: changing max per route
> 
> 
> I ran your code and did not see a single log entry with
> 'max-allowed=50'.
> 
> Oleg
> 



---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


Re: pooling connection manager: changing max per route

Posted by Pete Keyes <PK...@starbucks.com>.
Thank you.  Just to make sure . . . you used apache-hc version 4.4.1 for this test?

—
Pete Keyes
Starbucks Coffee Co.
w: 206-318-5933
c: 206-914-4134


From: "olegk@apache.org<ma...@apache.org>" <ol...@apache.org>>
Reply-To: HttpClient Discussion <ht...@hc.apache.org>>
Date: Thursday, February 25, 2016 at 3:25 AM
To: HttpClient Discussion <ht...@hc.apache.org>>
Subject: Re: pooling connection manager: changing max per route


I ran your code and did not see a single log entry with
'max-allowed=50'.

Oleg


Re: pooling connection manager: changing max per route

Posted by Oleg Kalnichevski <ol...@apache.org>.
On Wed, 2016-02-24 at 01:23 +0000, Pete Keyes wrote:
> I think this is a valid example. Code below produces the following I/O on stdout.  Max routes for the specific Route is set to 200.  The default for the connection pool manager is 50.
> 
> [Tue Feb 23 17:05:11 PST 2016]static http-deliver init starting...
> [Tue Feb 23 17:05:11 PST 2016]init hc ssl context...
> [Tue Feb 23 17:05:12 PST 2016]init hc 'allow-all' ssl socket factory...
> [Tue Feb 23 17:05:12 PST 2016]init hc 'allow-all' ssl registry...
> [Tue Feb 23 17:05:12 PST 2016]init hc 'allow-all' connection manager...
> [Tue Feb 23 17:05:12 PST 2016]creating common http-client:; conn-timeout=120000ms; conns-max=100000; so-timeout=120000ms
> [Tue Feb 23 17:05:12 PST 2016]starting http-client connection monitor thread...
> [Tue Feb 23 17:05:12 PST 2016]http-client connection pool monitor started.
> 
> logs specific route max
> [Tue Feb 23 17:05:12 PST 2016]set route max-conns:; max-allowed=200; protocol-host-port=https://lx01796:2443; httpRoute={}->https://lx01796:2443
> 
> pool monitor logs stats from pool manager.  value is 50 rather than 200
> [Tue Feb 23 17:05:13 PST 2016]emit telemetry message: type=hc-conn-pool; route=lx01796; available=0; active=1; blocking=0; max-allowed=50; server-nm=localhost:0000
> 
> [Tue Feb 23 17:05:13 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=1; blocking=0; max-allowed=100000; server-nm=localhost:0000
> [Tue Feb 23 17:05:14 PST 2016]emit telemetry message: type=hc-conn-pool; route=lx01796; available=0; active=1; blocking=0; max-allowed=50; server-nm=localhost:0000
> [Tue Feb 23 17:05:14 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=1; blocking=0; max-allowed=100000; server-nm=localhost:0000
> [Tue Feb 23 17:05:14 PST 2016]response code: 500
> [Tue Feb 23 17:05:15 PST 2016]emit telemetry message: type=hc-conn-pool; route=lx01796; available=0; active=0; blocking=0; max-allowed=50; server-nm=localhost:0000
> [Tue Feb 23 17:05:15 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=0; blocking=0; max-allowed=100000; server-nm=localhost:0000
> [Tue Feb 23 17:05:16 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=0; blocking=0; max-allowed=100000; server-nm=localhost:0000
> 

I ran your code and did not see a single log entry with
'max-allowed=50'.

Oleg

> 
> 
> Test Case Code:
> package com.sbux.junk;
> 
> import java.net.URL;
> import java.nio.charset.Charset;
> import java.util.Date;
> import java.util.Set;
> import java.util.concurrent.TimeUnit;
> import java.util.concurrent.atomic.AtomicBoolean;
> import javax.net.ssl.HostnameVerifier;
> import javax.net.ssl.SSLContext;
> import org.apache.http.HttpHost;
> import org.apache.http.HttpResponse;
> import org.apache.http.auth.AuthScope;
> import org.apache.http.auth.UsernamePasswordCredentials;
> import org.apache.http.client.AuthCache;
> import org.apache.http.client.CredentialsProvider;
> import org.apache.http.client.config.CookieSpecs;
> import org.apache.http.client.config.RequestConfig;
> import org.apache.http.client.methods.HttpGet;
> import org.apache.http.client.methods.HttpRequestBase;
> import org.apache.http.client.protocol.HttpClientContext;
> import org.apache.http.config.ConnectionConfig;
> import org.apache.http.config.Registry;
> import org.apache.http.config.RegistryBuilder;
> import org.apache.http.config.SocketConfig;
> import org.apache.http.conn.routing.HttpRoute;
> import org.apache.http.conn.socket.ConnectionSocketFactory;
> import org.apache.http.conn.socket.PlainConnectionSocketFactory;
> import org.apache.http.conn.ssl.NoopHostnameVerifier;
> import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
> import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
> import org.apache.http.impl.auth.BasicScheme;
> import org.apache.http.impl.client.BasicAuthCache;
> import org.apache.http.impl.client.BasicCredentialsProvider;
> import org.apache.http.impl.client.CloseableHttpClient;
> import org.apache.http.impl.client.HttpClientBuilder;
> import org.apache.http.impl.client.HttpClients;
> import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
> import org.apache.http.pool.PoolStats;
> import org.apache.http.ssl.SSLContexts;
> import org.apache.logging.log4j.Marker;
> import org.apache.logging.log4j.MarkerManager;
> 
> 
> 
> public class HttpClientConnLimitTest {
>     private static PoolingHttpClientConnectionManager globalConnManagerPool;
>     private static Thread globalConnManagerThread;
>     private static CloseableHttpClient globalHttpClient;
>     public static final HostnameVerifier ALLOW_ALL_VERIFIER = NoopHostnameVerifier.INSTANCE;
>     public static final int DEFAULT_MAX_CONNECTIONS = 10000;
>     public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 50;
>     public static final int DEFAULT_MAX_INACTIVITY_MS = 1000*60;
>     public static final long DEFAULT_MAX_CONN_IDLE_MINUTES = 5;
>     public static final int DEFAULT_DEFAULT_CONNECT_TIMEOUT_MS = 120000;
>     public static final int DEFAULT_DEFAULT_SO_TIMEOUT_MS = 120000;
>     public static final int DEFAULT_DEFAULT_RCV_BUFFER_BYTES = 2048;
>     public static final int DEFAULT_DEFAULT_SND_BUFFER_BYTES = 2048;
>     public static final String DEFAULT_DEFAULT_SOCKET_SO_KEEPALIVE_FLAG = "yes";
>     public static final String DEFAULT_HAWS_HTTP_CLIENT_CONNECTION_MONITOR = "yes";
> 
> 
>     private static final AtomicBoolean singletonsInitialized = new AtomicBoolean(false);
> 
>     private static void log(String s) {
>         System.out.println("[" + new Date() + "]" + s);
>     }
>     private static void pause(long l) {
>         try { Thread.sleep(l); } catch(Throwable t) {}
>     }
> 
>     private static void initSingletons() throws Exception {
>         final boolean done = singletonsInitialized.getAndSet(true);
>         if(done) {
>             return;
>         }
> 
>         log("static http-deliver init starting...");
>         log("init hc ssl context...");
>         SSLContext sslContext;
>         sslContext = SSLContexts.custom().useProtocol("TLS")
>             .loadTrustMaterial(null, new TrustSelfSignedStrategy())
>             .build()
>         ;
>         log("init hc 'allow-all' ssl socket factory...");
>         final SSLConnectionSocketFactory sslConnSocketFactory = new SSLConnectionSocketFactory(
>             sslContext
>             , ALLOW_ALL_VERIFIER
>         );
>         log("init hc 'allow-all' ssl registry...");
>         final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
>             .register("http", PlainConnectionSocketFactory.getSocketFactory())
>             .register("https", sslConnSocketFactory)
>             .build()
>         ;
> 
>         log("init hc 'allow-all' connection manager...");
>         globalConnManagerPool = new PoolingHttpClientConnectionManager(
>             registry
>         );
> 
>         /*
>          * setup the connection pool manager defaults
>          */
>         globalConnManagerPool.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);
>         globalConnManagerPool.setMaxTotal(100000);
>         globalConnManagerPool.setValidateAfterInactivity(30000);
> 
>         log("creating common http-client:"
>             + "; conn-timeout=" + 120000 + "ms"
>             + "; conns-max=" + 100000
>             + "; so-timeout=" + 120000 + "ms"
>         );
>         final RequestConfig requestConfig = RequestConfig.copy(RequestConfig.DEFAULT)
>             .setConnectTimeout(120000)
>             .setConnectionRequestTimeout(120000)
>             .setCookieSpec(CookieSpecs.DEFAULT)
>             .setSocketTimeout(120000)
>             .build()
>         ;
> 
>         /*
>          * create http client for this bean - same for all env's
>          *
>          * each env specific execution will have private http client context
>          */
>         final Charset charset = Charset.forName("utf-8");
>         final ConnectionConfig connConfig = ConnectionConfig.copy(ConnectionConfig.DEFAULT)
>             .setCharset(charset)
>             .build()
>         ;
> 
>         // build custom socket config
>         final SocketConfig socketConfig = SocketConfig.copy(SocketConfig.DEFAULT)
>             .setRcvBufSize(2048)
>             .setSndBufSize(2048)
>             .setSoKeepAlive(true)
>             .setSoTimeout(120000)
>             .build()
>         ;
>         final HttpClientBuilder builder = HttpClients.custom()
>             .setConnectionManager(globalConnManagerPool)
>             .setConnectionManagerShared(true)
>             .setConnectionTimeToLive(DEFAULT_MAX_CONN_IDLE_MINUTES, TimeUnit.MINUTES)
>             .setDefaultConnectionConfig(connConfig)
>             .setDefaultRequestConfig(requestConfig)
>             .setMaxConnPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE)
>             .setDefaultSocketConfig(socketConfig)
>             .setMaxConnTotal(100000)
>             .useSystemProperties()
>         ;
> 
>         /*
>          * disable hostname verification ... if needed
>          */
>         builder.setSSLHostnameVerifier(ALLOW_ALL_VERIFIER);
> 
>         // add CloseableHttpClient to the map
>         globalHttpClient = builder.build();
> 
>         globalConnManagerThread = new Thread() {
>             final Marker marker = MarkerManager.getMarker("http-pool");
>             private void cleanupPools() throws Exception {
>                 globalConnManagerPool.closeExpiredConnections();
>                 globalConnManagerPool.closeIdleConnections(
>                     5, TimeUnit.MINUTES
>                 );
>             }
> 
>             private void getPoolStats(
>                 final PoolingHttpClientConnectionManager cm
>             )
>             {
>                 try {
>                     /*
>                      * inspect pool by route
>                      */
>                     Set<HttpRoute> routes = cm.getRoutes();
>                     if(routes != null && !routes.isEmpty()) {
>                         for(final HttpRoute r : routes) {
>                             final String hostname = r.getTargetHost().getHostName();
> 
>                             // get pool stats for route
>                             final PoolStats ps = cm.getStats(r);
>                             final int available = ps.getAvailable();
>                             final int active = ps.getLeased();
>                             final int limit = ps.getMax();
>                             final int blocking = ps.getPending();
> 
>                             String s = "emit telemetry message:"
>                                 + " type=hc-conn-pool"
>                                 + "; route=" + hostname
>                                 + "; available=" + available
>                                 + "; active=" + active
>                                 + "; blocking=" + blocking
>                                 + "; max-allowed=" + limit
>                                 + "; server-nm=" + "localhost:0000"
>                             ;
>                             log(s);
>                         }
>                     }
> 
>                     /*
>                      * inspect pool globally across all routes
>                      */
>                     PoolStats tps = cm.getTotalStats();
>                     int available = tps.getAvailable();
>                     int active = tps.getLeased();
>                     int limit = tps.getMax();
>                     int blocking = tps.getPending();
>                     String s = "emit telemetry message:"
>                         + " type=hc-conn-pool"
>                         + "; route=all-routes"
>                         + "; available=" + available
>                         + "; active=" + active
>                         + "; blocking=" + blocking
>                         + "; max-allowed=" + limit
>                         + "; server-nm=" + "localhost:0000"
>                     ;
>                     log(s);
>                 }
>                 catch(Throwable t) {
>                     log("failed to log http-client connection pool stats: " + t);
>                     t.printStackTrace(System.out);
>                 }
>             }
> 
>             private void logPoolStats() throws Exception {
>                 getPoolStats(globalConnManagerPool);
>             }
> 
>             @Override public void run() {
>                 log("http-client connection pool monitor started.");
>                 while(true) {
>                     pause(1000);
>                     try {
>                         logPoolStats();
>                         cleanupPools();
>                     }
>                     catch(Throwable t) {
>                         log("http connection monitor error: " + t);
>                         t.printStackTrace(System.out);
>                     }
>                 }
>             }
>         };
> 
>         log("starting http-client connection monitor thread...");
>         globalConnManagerThread.setDaemon(true);
>         globalConnManagerThread.start();
>     }
> 
>     private static void startRequestor() throws Exception {
>         Thread t = new Thread() {
>             private RequestConfig requestConfig;
> 
>             @Override public void run() {
>                 final RequestConfig requestConfig = RequestConfig.copy(RequestConfig.DEFAULT)
>                     .setAuthenticationEnabled(true)
>                     .setConnectTimeout(120000)
>                     .setConnectionRequestTimeout(120000)
>                     .setExpectContinueEnabled(true)
>                     .setRedirectsEnabled(false)
>                     .setSocketTimeout(120000)
>                     .build()
>                 ;
> 
>                 URL url=null;
>                 try {
>                     url = new URL("https://HOSTNAME:PORTNO/GET/SERVICE/URI");
>                 }
>                 catch(Throwable t) {
>                     log("can't parse url");
>                     t.printStackTrace(System.out);
>                 }
> 
>                 final String urlText = url.toString();
>                 final String host = url.getHost();
>                 final int portNo = url.getPort(); // == -1 ? url.getDefaultPort() : url.getPort();
>                 final String protocol = url.getProtocol();
>                 final HttpHost httpHost = new HttpHost(host, portNo, protocol);
>                 final HttpRoute httpRoute = new HttpRoute(httpHost);
>                 globalConnManagerPool.setMaxPerRoute(httpRoute, 200);
>                 log("set route max-conns:"
>                     + "; max-allowed=" + 200
>                     + "; protocol-host-port=" + protocol + "://" + host + ":" + portNo
>                     + "; httpRoute=" + String.valueOf(httpRoute)
>                 );
> 
>                 final String username = "USERNAME HERE";
>                 final String password = "PASSWORD HERE";
>                 final AuthCache authCache;
>                 final CredentialsProvider credsProvider;
>                 final AuthScope authScope = new AuthScope(url.getHost(), portNo);
>                 final UsernamePasswordCredentials basic = new UsernamePasswordCredentials(username, password);
>                 credsProvider = new BasicCredentialsProvider();
>                 credsProvider.setCredentials(authScope, basic);
> 
>                 // create authentication cache for preemptive authorization
>                 authCache = new BasicAuthCache();
>                 final BasicScheme basicScheme = new BasicScheme();
>                 authCache.put(httpHost, basicScheme);
>                 HttpClientContext httpContext = HttpClientContext.create();
>                 httpContext.setAuthCache(authCache);
>                 httpContext.setCredentialsProvider(credsProvider);
>                 httpContext.setRequestConfig(requestConfig);
> 
>                 for(int i=0; i < 100; i++) {
>                     pause(250);
>                     try {
>                         HttpRequestBase method = new HttpGet(urlText);
>                         method.setHeader("gws-requestId", "pkut-"+System.currentTimeMillis());
>                         method.setHeader("gws-audit", "pk");
>                         method.setHeader("gws-environment", "ps");
>                         method.setHeader("gws-version", "1");
> 
>                         HttpResponse response = globalHttpClient.execute(method, httpContext);
>                         log("response code: " + response.getStatusLine().getStatusCode());
>                         response.getEntity().getContent().close();
>                     }
>                     catch(Throwable t) {
>                         log("error invoking service: " + t);
>                         t.printStackTrace(System.out);
>                     }
>                 }
>             }
>         };
>         t.start();
>     }
> 
>     public static void main(String args[]) throws Exception {
>         initSingletons();
>         for(int i=0; i < 10; i++) {
>             startRequestor();
>         }
>         pause(1000*5);
>     }
> }
> 
> —
> Pete
> 
> 
> From: "olegk@apache.org<ma...@apache.org>" <ol...@apache.org>>
> Reply-To: HttpClient Discussion <ht...@hc.apache.org>>
> Date: Tuesday, February 23, 2016 at 11:07 AM
> To: HttpClient Discussion <ht...@hc.apache.org>>
> Subject: Re: pooling connection manager: changing max per route
> 
> On Tue, 2016-02-23 at 01:11 +0000, Pete Keyes wrote:
> version: 4.4.1
> App Server: TomEE7
> We use PoolingHttpClientConnectionManager with the following defaults:
>    *   max total connections: 100,000
>    *   default max per route: 50
> we create the HttpClient and PoolingHttpClientConnectionManager as static singletons at container startup.
> private static Thread globalConnManagerThread;
> private static CloseableHttpClient globalHttpClient;
> static {
>          // create global pooling connection manager
>          globalConnManagerPool = new PoolingHttpClientConnectionManager(
>              registry
>          );
>          globalConnManagerPool.setDefaultMaxPerRoute(50);
>          globalConnManagerPool.setMaxTotal(100000);
>          // create global HttpClient instance
>          final HttpClientBuilder builder = HttpClients.custom()
>              .setConnectionManager(globalConnManagerPool)
>              .setConnectionManagerShared(true)
>              .setConnectionTimeToLive(5, TimeUnit.MINUTES)
>              .setDefaultConnectionConfig(connConfig)
>              .setDefaultRequestConfig(requestConfig)
>              .setMaxConnPerRoute(50)  // <<== default per route is 50
>              .setDefaultSocketConfig(socketConfig)
>              .setMaxConnTotal(100000)
>              .setRetryHandler(httpRetryHandler)
>              .useSystemProperties()
>          ;
> 
> Please note that connection level parameters will have no effect when
> the connection manager is explicitly set. Please have a look at
> Javadocs.
> 
> 
>          CloseableHttpClient globalHttpClient = builder.build();
> }
> We set the max per specific route with the following code snippet:
> @PostConstruct public void init() {
>      List<URL> allUrls = getAllUrls();
>      for(final URL url : allUrls) {
>          HttpServiceConfig hsc = getHttpServiceConfig(url);
>          final String host = url.getHost();
>          final int portNo = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
>          final String protocol = url.getProtocol();
>          final HttpHost httpHost = new HttpHost(host, portNo, protocol);
>          final HttpRoute httpRoute = new HttpRoute(httpHost);
>          globalConnManagerPool.setMaxPerRoute(httpRoute, 200);  // <<== max set to 200 for route
>          log.info(gMarker, "set route max-conns:"
>              + "; max-allowed=" + hsc.getMaxConns()
>              + "; protocol-host-port=" + protocol + "://" + host + ":" + portNo
>              + "; httpRoute=" + String.valueOf(httpRoute)
>          );
>      }
> }
> we see each route specific max connection log message at startup.  for instance:
> set route max-conns: conns-max=200; protocol-host-port=https://some-host:443; httpRoute={}->https://some-host:443
> we have a background thread that monitors the apache-hc connection pool statistics and emits log messages.  we see the following apache-hc connection manager pool “route specific” statistics logged:
> private void logPoolStats() {
>      Set<HttpRoute> routes = globalConnManagerPool.getRoutes();
>      for(final HttpRoute r : routes) {
>          final PoolStats ps = cm.getStats(r);
>          final int available = ps.getAvailable();
>          final int active = ps.getLeased();
>          final int limit = ps.getMax();
>          final int blocking = ps.getPending();
>          String s = "emit statistic:"
>              + " type=hc-conn-pool"
>              + "; route=" + hostname
>              + "; available=" + available
>              + "; active=" + active
>              + "; blocking=" + blocking
>              + "; max-allowed=" + limit
>              + "; server-nm=" + Helpers.getLocalHost() + ":" + Helpers.getServerHttpsPort()
>          ;
>          log.info(marker, s);
>      }
> }
> we see log messages like the following from the apache-hc connection pool monitor logging:
> emit statistic: type=hc-conn-pool; route=some-host; available=1; active=0; blocking=0; max-allowed=50
> The connection manager isn’t respecting the per-route connection settings.  Above we see that the “max-allowed” per route reported by the pool-manager is 50 for a route that specifically set the max-allowed to 200.
> Any hints about what we are doing wrong to override the limit on a per-route basis?
> 
> Could you please try to reproduce the issue with a test case?
> 
> Oleg
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org<ma...@hc.apache.org>
> For additional commands, e-mail: httpclient-users-help@hc.apache.org<ma...@hc.apache.org>
> 
> 



---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


Re: pooling connection manager: changing max per route

Posted by Pete Keyes <PK...@starbucks.com>.
I think this is a valid example. Code below produces the following I/O on stdout.  Max routes for the specific Route is set to 200.  The default for the connection pool manager is 50.

[Tue Feb 23 17:05:11 PST 2016]static http-deliver init starting...
[Tue Feb 23 17:05:11 PST 2016]init hc ssl context...
[Tue Feb 23 17:05:12 PST 2016]init hc 'allow-all' ssl socket factory...
[Tue Feb 23 17:05:12 PST 2016]init hc 'allow-all' ssl registry...
[Tue Feb 23 17:05:12 PST 2016]init hc 'allow-all' connection manager...
[Tue Feb 23 17:05:12 PST 2016]creating common http-client:; conn-timeout=120000ms; conns-max=100000; so-timeout=120000ms
[Tue Feb 23 17:05:12 PST 2016]starting http-client connection monitor thread...
[Tue Feb 23 17:05:12 PST 2016]http-client connection pool monitor started.

logs specific route max
[Tue Feb 23 17:05:12 PST 2016]set route max-conns:; max-allowed=200; protocol-host-port=https://lx01796:2443; httpRoute={}->https://lx01796:2443

pool monitor logs stats from pool manager.  value is 50 rather than 200
[Tue Feb 23 17:05:13 PST 2016]emit telemetry message: type=hc-conn-pool; route=lx01796; available=0; active=1; blocking=0; max-allowed=50; server-nm=localhost:0000

[Tue Feb 23 17:05:13 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=1; blocking=0; max-allowed=100000; server-nm=localhost:0000
[Tue Feb 23 17:05:14 PST 2016]emit telemetry message: type=hc-conn-pool; route=lx01796; available=0; active=1; blocking=0; max-allowed=50; server-nm=localhost:0000
[Tue Feb 23 17:05:14 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=1; blocking=0; max-allowed=100000; server-nm=localhost:0000
[Tue Feb 23 17:05:14 PST 2016]response code: 500
[Tue Feb 23 17:05:15 PST 2016]emit telemetry message: type=hc-conn-pool; route=lx01796; available=0; active=0; blocking=0; max-allowed=50; server-nm=localhost:0000
[Tue Feb 23 17:05:15 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=0; blocking=0; max-allowed=100000; server-nm=localhost:0000
[Tue Feb 23 17:05:16 PST 2016]emit telemetry message: type=hc-conn-pool; route=all-routes; available=0; active=0; blocking=0; max-allowed=100000; server-nm=localhost:0000



Test Case Code:
package com.sbux.junk;

import java.net.URL;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.apache.http.ssl.SSLContexts;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;



public class HttpClientConnLimitTest {
    private static PoolingHttpClientConnectionManager globalConnManagerPool;
    private static Thread globalConnManagerThread;
    private static CloseableHttpClient globalHttpClient;
    public static final HostnameVerifier ALLOW_ALL_VERIFIER = NoopHostnameVerifier.INSTANCE;
    public static final int DEFAULT_MAX_CONNECTIONS = 10000;
    public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 50;
    public static final int DEFAULT_MAX_INACTIVITY_MS = 1000*60;
    public static final long DEFAULT_MAX_CONN_IDLE_MINUTES = 5;
    public static final int DEFAULT_DEFAULT_CONNECT_TIMEOUT_MS = 120000;
    public static final int DEFAULT_DEFAULT_SO_TIMEOUT_MS = 120000;
    public static final int DEFAULT_DEFAULT_RCV_BUFFER_BYTES = 2048;
    public static final int DEFAULT_DEFAULT_SND_BUFFER_BYTES = 2048;
    public static final String DEFAULT_DEFAULT_SOCKET_SO_KEEPALIVE_FLAG = "yes";
    public static final String DEFAULT_HAWS_HTTP_CLIENT_CONNECTION_MONITOR = "yes";


    private static final AtomicBoolean singletonsInitialized = new AtomicBoolean(false);

    private static void log(String s) {
        System.out.println("[" + new Date() + "]" + s);
    }
    private static void pause(long l) {
        try { Thread.sleep(l); } catch(Throwable t) {}
    }

    private static void initSingletons() throws Exception {
        final boolean done = singletonsInitialized.getAndSet(true);
        if(done) {
            return;
        }

        log("static http-deliver init starting...");
        log("init hc ssl context...");
        SSLContext sslContext;
        sslContext = SSLContexts.custom().useProtocol("TLS")
            .loadTrustMaterial(null, new TrustSelfSignedStrategy())
            .build()
        ;
        log("init hc 'allow-all' ssl socket factory...");
        final SSLConnectionSocketFactory sslConnSocketFactory = new SSLConnectionSocketFactory(
            sslContext
            , ALLOW_ALL_VERIFIER
        );
        log("init hc 'allow-all' ssl registry...");
        final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", sslConnSocketFactory)
            .build()
        ;

        log("init hc 'allow-all' connection manager...");
        globalConnManagerPool = new PoolingHttpClientConnectionManager(
            registry
        );

        /*
         * setup the connection pool manager defaults
         */
        globalConnManagerPool.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);
        globalConnManagerPool.setMaxTotal(100000);
        globalConnManagerPool.setValidateAfterInactivity(30000);

        log("creating common http-client:"
            + "; conn-timeout=" + 120000 + "ms"
            + "; conns-max=" + 100000
            + "; so-timeout=" + 120000 + "ms"
        );
        final RequestConfig requestConfig = RequestConfig.copy(RequestConfig.DEFAULT)
            .setConnectTimeout(120000)
            .setConnectionRequestTimeout(120000)
            .setCookieSpec(CookieSpecs.DEFAULT)
            .setSocketTimeout(120000)
            .build()
        ;

        /*
         * create http client for this bean - same for all env's
         *
         * each env specific execution will have private http client context
         */
        final Charset charset = Charset.forName("utf-8");
        final ConnectionConfig connConfig = ConnectionConfig.copy(ConnectionConfig.DEFAULT)
            .setCharset(charset)
            .build()
        ;

        // build custom socket config
        final SocketConfig socketConfig = SocketConfig.copy(SocketConfig.DEFAULT)
            .setRcvBufSize(2048)
            .setSndBufSize(2048)
            .setSoKeepAlive(true)
            .setSoTimeout(120000)
            .build()
        ;
        final HttpClientBuilder builder = HttpClients.custom()
            .setConnectionManager(globalConnManagerPool)
            .setConnectionManagerShared(true)
            .setConnectionTimeToLive(DEFAULT_MAX_CONN_IDLE_MINUTES, TimeUnit.MINUTES)
            .setDefaultConnectionConfig(connConfig)
            .setDefaultRequestConfig(requestConfig)
            .setMaxConnPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE)
            .setDefaultSocketConfig(socketConfig)
            .setMaxConnTotal(100000)
            .useSystemProperties()
        ;

        /*
         * disable hostname verification ... if needed
         */
        builder.setSSLHostnameVerifier(ALLOW_ALL_VERIFIER);

        // add CloseableHttpClient to the map
        globalHttpClient = builder.build();

        globalConnManagerThread = new Thread() {
            final Marker marker = MarkerManager.getMarker("http-pool");
            private void cleanupPools() throws Exception {
                globalConnManagerPool.closeExpiredConnections();
                globalConnManagerPool.closeIdleConnections(
                    5, TimeUnit.MINUTES
                );
            }

            private void getPoolStats(
                final PoolingHttpClientConnectionManager cm
            )
            {
                try {
                    /*
                     * inspect pool by route
                     */
                    Set<HttpRoute> routes = cm.getRoutes();
                    if(routes != null && !routes.isEmpty()) {
                        for(final HttpRoute r : routes) {
                            final String hostname = r.getTargetHost().getHostName();

                            // get pool stats for route
                            final PoolStats ps = cm.getStats(r);
                            final int available = ps.getAvailable();
                            final int active = ps.getLeased();
                            final int limit = ps.getMax();
                            final int blocking = ps.getPending();

                            String s = "emit telemetry message:"
                                + " type=hc-conn-pool"
                                + "; route=" + hostname
                                + "; available=" + available
                                + "; active=" + active
                                + "; blocking=" + blocking
                                + "; max-allowed=" + limit
                                + "; server-nm=" + "localhost:0000"
                            ;
                            log(s);
                        }
                    }

                    /*
                     * inspect pool globally across all routes
                     */
                    PoolStats tps = cm.getTotalStats();
                    int available = tps.getAvailable();
                    int active = tps.getLeased();
                    int limit = tps.getMax();
                    int blocking = tps.getPending();
                    String s = "emit telemetry message:"
                        + " type=hc-conn-pool"
                        + "; route=all-routes"
                        + "; available=" + available
                        + "; active=" + active
                        + "; blocking=" + blocking
                        + "; max-allowed=" + limit
                        + "; server-nm=" + "localhost:0000"
                    ;
                    log(s);
                }
                catch(Throwable t) {
                    log("failed to log http-client connection pool stats: " + t);
                    t.printStackTrace(System.out);
                }
            }

            private void logPoolStats() throws Exception {
                getPoolStats(globalConnManagerPool);
            }

            @Override public void run() {
                log("http-client connection pool monitor started.");
                while(true) {
                    pause(1000);
                    try {
                        logPoolStats();
                        cleanupPools();
                    }
                    catch(Throwable t) {
                        log("http connection monitor error: " + t);
                        t.printStackTrace(System.out);
                    }
                }
            }
        };

        log("starting http-client connection monitor thread...");
        globalConnManagerThread.setDaemon(true);
        globalConnManagerThread.start();
    }

    private static void startRequestor() throws Exception {
        Thread t = new Thread() {
            private RequestConfig requestConfig;

            @Override public void run() {
                final RequestConfig requestConfig = RequestConfig.copy(RequestConfig.DEFAULT)
                    .setAuthenticationEnabled(true)
                    .setConnectTimeout(120000)
                    .setConnectionRequestTimeout(120000)
                    .setExpectContinueEnabled(true)
                    .setRedirectsEnabled(false)
                    .setSocketTimeout(120000)
                    .build()
                ;

                URL url=null;
                try {
                    url = new URL("https://HOSTNAME:PORTNO/GET/SERVICE/URI");
                }
                catch(Throwable t) {
                    log("can't parse url");
                    t.printStackTrace(System.out);
                }

                final String urlText = url.toString();
                final String host = url.getHost();
                final int portNo = url.getPort(); // == -1 ? url.getDefaultPort() : url.getPort();
                final String protocol = url.getProtocol();
                final HttpHost httpHost = new HttpHost(host, portNo, protocol);
                final HttpRoute httpRoute = new HttpRoute(httpHost);
                globalConnManagerPool.setMaxPerRoute(httpRoute, 200);
                log("set route max-conns:"
                    + "; max-allowed=" + 200
                    + "; protocol-host-port=" + protocol + "://" + host + ":" + portNo
                    + "; httpRoute=" + String.valueOf(httpRoute)
                );

                final String username = "USERNAME HERE";
                final String password = "PASSWORD HERE";
                final AuthCache authCache;
                final CredentialsProvider credsProvider;
                final AuthScope authScope = new AuthScope(url.getHost(), portNo);
                final UsernamePasswordCredentials basic = new UsernamePasswordCredentials(username, password);
                credsProvider = new BasicCredentialsProvider();
                credsProvider.setCredentials(authScope, basic);

                // create authentication cache for preemptive authorization
                authCache = new BasicAuthCache();
                final BasicScheme basicScheme = new BasicScheme();
                authCache.put(httpHost, basicScheme);
                HttpClientContext httpContext = HttpClientContext.create();
                httpContext.setAuthCache(authCache);
                httpContext.setCredentialsProvider(credsProvider);
                httpContext.setRequestConfig(requestConfig);

                for(int i=0; i < 100; i++) {
                    pause(250);
                    try {
                        HttpRequestBase method = new HttpGet(urlText);
                        method.setHeader("gws-requestId", "pkut-"+System.currentTimeMillis());
                        method.setHeader("gws-audit", "pk");
                        method.setHeader("gws-environment", "ps");
                        method.setHeader("gws-version", "1");

                        HttpResponse response = globalHttpClient.execute(method, httpContext);
                        log("response code: " + response.getStatusLine().getStatusCode());
                        response.getEntity().getContent().close();
                    }
                    catch(Throwable t) {
                        log("error invoking service: " + t);
                        t.printStackTrace(System.out);
                    }
                }
            }
        };
        t.start();
    }

    public static void main(String args[]) throws Exception {
        initSingletons();
        for(int i=0; i < 10; i++) {
            startRequestor();
        }
        pause(1000*5);
    }
}

—
Pete


From: "olegk@apache.org<ma...@apache.org>" <ol...@apache.org>>
Reply-To: HttpClient Discussion <ht...@hc.apache.org>>
Date: Tuesday, February 23, 2016 at 11:07 AM
To: HttpClient Discussion <ht...@hc.apache.org>>
Subject: Re: pooling connection manager: changing max per route

On Tue, 2016-02-23 at 01:11 +0000, Pete Keyes wrote:
version: 4.4.1
App Server: TomEE7
We use PoolingHttpClientConnectionManager with the following defaults:
   *   max total connections: 100,000
   *   default max per route: 50
we create the HttpClient and PoolingHttpClientConnectionManager as static singletons at container startup.
private static Thread globalConnManagerThread;
private static CloseableHttpClient globalHttpClient;
static {
         // create global pooling connection manager
         globalConnManagerPool = new PoolingHttpClientConnectionManager(
             registry
         );
         globalConnManagerPool.setDefaultMaxPerRoute(50);
         globalConnManagerPool.setMaxTotal(100000);
         // create global HttpClient instance
         final HttpClientBuilder builder = HttpClients.custom()
             .setConnectionManager(globalConnManagerPool)
             .setConnectionManagerShared(true)
             .setConnectionTimeToLive(5, TimeUnit.MINUTES)
             .setDefaultConnectionConfig(connConfig)
             .setDefaultRequestConfig(requestConfig)
             .setMaxConnPerRoute(50)  // <<== default per route is 50
             .setDefaultSocketConfig(socketConfig)
             .setMaxConnTotal(100000)
             .setRetryHandler(httpRetryHandler)
             .useSystemProperties()
         ;

Please note that connection level parameters will have no effect when
the connection manager is explicitly set. Please have a look at
Javadocs.


         CloseableHttpClient globalHttpClient = builder.build();
}
We set the max per specific route with the following code snippet:
@PostConstruct public void init() {
     List<URL> allUrls = getAllUrls();
     for(final URL url : allUrls) {
         HttpServiceConfig hsc = getHttpServiceConfig(url);
         final String host = url.getHost();
         final int portNo = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
         final String protocol = url.getProtocol();
         final HttpHost httpHost = new HttpHost(host, portNo, protocol);
         final HttpRoute httpRoute = new HttpRoute(httpHost);
         globalConnManagerPool.setMaxPerRoute(httpRoute, 200);  // <<== max set to 200 for route
         log.info(gMarker, "set route max-conns:"
             + "; max-allowed=" + hsc.getMaxConns()
             + "; protocol-host-port=" + protocol + "://" + host + ":" + portNo
             + "; httpRoute=" + String.valueOf(httpRoute)
         );
     }
}
we see each route specific max connection log message at startup.  for instance:
set route max-conns: conns-max=200; protocol-host-port=https://some-host:443; httpRoute={}->https://some-host:443
we have a background thread that monitors the apache-hc connection pool statistics and emits log messages.  we see the following apache-hc connection manager pool “route specific” statistics logged:
private void logPoolStats() {
     Set<HttpRoute> routes = globalConnManagerPool.getRoutes();
     for(final HttpRoute r : routes) {
         final PoolStats ps = cm.getStats(r);
         final int available = ps.getAvailable();
         final int active = ps.getLeased();
         final int limit = ps.getMax();
         final int blocking = ps.getPending();
         String s = "emit statistic:"
             + " type=hc-conn-pool"
             + "; route=" + hostname
             + "; available=" + available
             + "; active=" + active
             + "; blocking=" + blocking
             + "; max-allowed=" + limit
             + "; server-nm=" + Helpers.getLocalHost() + ":" + Helpers.getServerHttpsPort()
         ;
         log.info(marker, s);
     }
}
we see log messages like the following from the apache-hc connection pool monitor logging:
emit statistic: type=hc-conn-pool; route=some-host; available=1; active=0; blocking=0; max-allowed=50
The connection manager isn’t respecting the per-route connection settings.  Above we see that the “max-allowed” per route reported by the pool-manager is 50 for a route that specifically set the max-allowed to 200.
Any hints about what we are doing wrong to override the limit on a per-route basis?

Could you please try to reproduce the issue with a test case?

Oleg


---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org<ma...@hc.apache.org>
For additional commands, e-mail: httpclient-users-help@hc.apache.org<ma...@hc.apache.org>



Re: pooling connection manager: changing max per route

Posted by Oleg Kalnichevski <ol...@apache.org>.
On Tue, 2016-02-23 at 01:11 +0000, Pete Keyes wrote:
> version: 4.4.1
> App Server: TomEE7
> 
> We use PoolingHttpClientConnectionManager with the following defaults:
> 
>   *   max total connections: 100,000
>   *   default max per route: 50
> 
> we create the HttpClient and PoolingHttpClientConnectionManager as static singletons at container startup.
> private static Thread globalConnManagerThread;
> private static CloseableHttpClient globalHttpClient;
> static {
>         // create global pooling connection manager
>         globalConnManagerPool = new PoolingHttpClientConnectionManager(
>             registry
>         );
>         globalConnManagerPool.setDefaultMaxPerRoute(50);
>         globalConnManagerPool.setMaxTotal(100000);
> 
>         // create global HttpClient instance
>         final HttpClientBuilder builder = HttpClients.custom()
>             .setConnectionManager(globalConnManagerPool)
>             .setConnectionManagerShared(true)
>             .setConnectionTimeToLive(5, TimeUnit.MINUTES)
>             .setDefaultConnectionConfig(connConfig)
>             .setDefaultRequestConfig(requestConfig)
>             .setMaxConnPerRoute(50)  // <<== default per route is 50
>             .setDefaultSocketConfig(socketConfig)
>             .setMaxConnTotal(100000)
>             .setRetryHandler(httpRetryHandler)
>             .useSystemProperties()
>         ;

Please note that connection level parameters will have no effect when
the connection manager is explicitly set. Please have a look at
Javadocs. 


>         CloseableHttpClient globalHttpClient = builder.build();
> }
> 
> We set the max per specific route with the following code snippet:
> 
> @PostConstruct public void init() {
>     List<URL> allUrls = getAllUrls();
>     for(final URL url : allUrls) {
>         HttpServiceConfig hsc = getHttpServiceConfig(url);
> 
>         final String host = url.getHost();
>         final int portNo = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
>         final String protocol = url.getProtocol();
>         final HttpHost httpHost = new HttpHost(host, portNo, protocol);
>         final HttpRoute httpRoute = new HttpRoute(httpHost);
>         globalConnManagerPool.setMaxPerRoute(httpRoute, 200);  // <<== max set to 200 for route
>         log.info(gMarker, "set route max-conns:"
>             + "; max-allowed=" + hsc.getMaxConns()
>             + "; protocol-host-port=" + protocol + "://" + host + ":" + portNo
>             + "; httpRoute=" + String.valueOf(httpRoute)
>         );
>     }
> }
> 
> 
> we see each route specific max connection log message at startup.  for instance:
> set route max-conns: conns-max=200; protocol-host-port=https://some-host:443; httpRoute={}->https://some-host:443
> 
> we have a background thread that monitors the apache-hc connection pool statistics and emits log messages.  we see the following apache-hc connection manager pool “route specific” statistics logged:
> private void logPoolStats() {
>     Set<HttpRoute> routes = globalConnManagerPool.getRoutes();
>     for(final HttpRoute r : routes) {
>         final PoolStats ps = cm.getStats(r);
>         final int available = ps.getAvailable();
>         final int active = ps.getLeased();
>         final int limit = ps.getMax();
>         final int blocking = ps.getPending();
> 
>         String s = "emit statistic:"
>             + " type=hc-conn-pool"
>             + "; route=" + hostname
>             + "; available=" + available
>             + "; active=" + active
>             + "; blocking=" + blocking
>             + "; max-allowed=" + limit
>             + "; server-nm=" + Helpers.getLocalHost() + ":" + Helpers.getServerHttpsPort()
>         ;
>         log.info(marker, s);
>     }
> }
> 
> we see log messages like the following from the apache-hc connection pool monitor logging:
> emit statistic: type=hc-conn-pool; route=some-host; available=1; active=0; blocking=0; max-allowed=50
> 
> The connection manager isn’t respecting the per-route connection settings.  Above we see that the “max-allowed” per route reported by the pool-manager is 50 for a route that specifically set the max-allowed to 200.
> 
> Any hints about what we are doing wrong to override the limit on a per-route basis?
> 

Could you please try to reproduce the issue with a test case?

Oleg


---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org