简体   繁体   中英

How to determine the maximum number of simultaneous connections for a given `HttpClient` instance

I have a Servlet that builds an HttpClient instance when it starts. It shares this client with a collaborating module used when servicing requests. I would like to use the FutureRequestExecutionService API within the collaborating module to easily send some requests concurrently. This requires using an HttpClient instance along with an ExecutorService instance. The tutorial recommends setting the ExecutorService to use the same number of threads as the HttpClient 's maximum number of concurrent connections.

The constructor for the futureRequestExecutionService takes any existing httpClient instance and an ExecutorService instance. When configuring both, it is important to align the maximum number of connections with the number of threads you are going to use. When there are more threads than connections, the connections may start timing out because there are no available connections. When there are more connections than threads, the futureRequestExecutionService will not use all of them.

I thought that the collaborating module should be the one creating the ExecutorService for its concurrent requests. The problem in that case is that the collaborating module does not necessarily know how many threads it should be using since it doesn't know how many simultaneous connections the HttpClient has been configured to allow.

I know I could use HttpClient 's getConnectionManager method, but as of 4.3 this is deprecated. So then what is the recommended way of ascertaining how many simultaneous connections a given HttpClient will allow? I suspect that the wrong answer is to save a reference to the ConnectionManager object used to build the HttpClient and pass it along with the collaborating module or to define some kind of global constant. Maybe I'm asking the wrong question.

Perhaps I should instead create the HttpClient , ExecutorService , and FutureRequestExecutionService objects all at the same time and then pass just the FutureRequestExecutionService instance to the modules that want to make HTTP requests using a shared client. I'd like to do this in a manner that is consistent with the intent of the authors of HttpClient; I'm just not sure in this case what that is exactly.

EDIT: To clarify, the HttpClient instance is created using an HttpClientBuilder that has a PoolingHttpClientConnectionManager set for its connection manager. However, this does not happen in the same scope as the creation of the PoolingHttpClientConnectionManager and FutureRequestExecutionService . I am starting to suspect that they should be created together and then instead of passing the HttpClient instance around, use the FutureRequestExecutionService instance.

The main point here is to avoid situations when too many worker threads end up contending for too few connections thus causing a performance bottleneck. The number of worker threads and connections per route / total limits just need to be about reasonable: say, 12 workers and 10 connections or 10 workers and 12 connections but not like 12 workers and 2 connections.

Having said all that, to answer your question I would not recommend tightly coupling of PoolingHttpClientConnectionManager and the FutureRequestExecutionService wiring code. To me a better approach should be having a simple POJO or even a hash map representing HTTP service configuration that all your wiring code should depend upon instead of direct coupling of various implementation classes.

Something along this line

static class MyHttpServiceConfig {
    int workerNum = 10;
};

MyHttpServiceConfig config = new MyHttpServiceConfig();

CloseableHttpClient client = HttpClients.custom()
        .setMaxConnPerRoute(config.workerNum)
        .build();

ExecutorService executor = Executors.newFixedThreadPool(config.workerNum);

FutureRequestExecutionService executionService = new FutureRequestExecutionService(
         client, executor);

You should use PoolingHttpClientConnectionManager to control the max number of httpClient connection can be used at the same time. And then you can pass in the httpClient you create with this connection manager into the FutureRequestExecutionService constructor.

An example is also provided by apache here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM