简体   繁体   中英

HttpClient can't get response from server

This problem has blocked our whole team half a day!

We use apache httpclient 4.3.x to post and get data from an storage server which provides http api. In order to improve performance, we used PoolingHttpClientConnectionManager :

public HttpClient createHttpClient() {
    Registry registry = RegistryBuilder.create()....build();
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
    connectionManager.setMaxTotal(50);
    connectionManager.setDefaultMaxPerRoute(50);

    CloseableHttpClient httpClient = HttpClients.custom()
       .setConnectionManager(connectionManager)
       .build();
    return httpClient;
}

Then we hold an instance of the httpClient in our program, reuse it with every http request:

Global httpClient:

HttpClient httpClient = createHttpClient();

Post some data:

HttpPost httpPut = new HttpPost("...");
HttpResponse response = httpClient.execute(httpPut);

// Notice we get the response content here!
String content = EntityUtils.toString(response.getEntity());
System.out.println(content);

httpPut.releaseConnection();
response.close();

Then get:

HttpGet httpGet = new HttpGet("...");

// Blocked at this line !!!!
HttpResponse response = httpClient.execute(httpGet);

String content = EntityUtils.toString(response.getEntity());
System.out.println(content);

httpPut.releaseConnection();
response.close();    

Please notice the line: // Blocked at this line !!!!

The program has blocked at that line and never go to next line. In debugging mode, I can see it has been blocked at:

SocketInputStream.socketRead0()

I've searched for a lot of questions and documents, but no lucky.


My colleage just fix it by setting NoConnectionReuseStrategy.INSTANCE :

 HttpClients.custom()
       .setConnectionManager(connectionManager)
       // Following line fixed the problem, but why?
       .setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE)
       .build();

Now it doens't blocked, but why?

What does "reuse connection" mean? And is there performance issue by using NoConnectionReuseStrategy ?

Thank you, guys~

I tried to reproduce the blocking http-get (also as an exercise for myself) but even without closing responses I could not get it to block. The ONLY time I managed to make the http-get block is by doing a response.getEntity().getContent() without reading from the returned InputStream and without closing the returned InputStream . For my tests I used Tomcat 7.0.47 with two very simple servlets (one responding "OK" to a get, the other echoing a post) as a server. The client started 50 threads with each thread performing 30 alternating http-get and http-post request (total of 1500 requests). The client did not use the RegistryBuilder , instead the default one is used (created by the PoolingHttpClientConnectionManager itself).

About the NoConnectionReuseStrategy : by default (HttpClient created with HttpClients.createDefault() , I used org.apache.httpcomponents:httpclient:4.3.1 ) a connection pool is used with a maximum of 2 connections to 1 server. Eg even if 5 threads are doing all kinds of requests at the same time to 1 server, the connection pool opens only 2 connections, re-uses them for all requests and ensures that 1 connection is used by 1 thread at any given time. This can have a very positive impact on client performance and significantly reduces load on the server. The only thing you must make sure is to call response.close() in a finally-block (this ensures the connection is returned to the connection pool). By using the NoConnectionReuseStrategy you basically disable the connection pool: for each request a new connection will be created. I recommend you enable debug-logging for category org.apache.http.impl.conn.PoolingHttpClientConnectionManager , it is very informative.

A note about httpPut.releaseConnection() : this does not actually release a connection, it only ensures that you can re-use the "httpPut" object in a next request (see the apidocs , follow the shown link). Also note that in your code for the "httpGet", you call releaseConnection() on "httpPut" instead of "httpGet".

Ran into this problem just a while back. In case someone else comes across this problem, this post might be useful.

I am using a Java Servlet to service my requests. When I wrote to the response stream using the PrintWriter instance my client blocked. Tried writing to the OutputStream directly response.getOutputStream.write("myresponse") and it worked.

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