28

I'm running load tests for my application. I have two servers: one with my application and a dummy-server that is responsible to get me responses.

In my dummy server I have the following jsp code:

<%@ page import="java.util.Random" %>
<%@ page language="java" %>
<%@ page session="false" %>
<%
   String retVal = "some json string";
   Thread.sleep(50);
%>

I'm running the application with tomcat7. My server.xml connection pool (in both servers) looks like:

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="1500" minSpareThreads="1000" prestartminSpareThreads="true" /> 
<Connector port="9031" protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           maxConnections="4000"
           executor="tomcatThreadPool"
           redirectPort="8443" />

The java code I'm running from the servers is:

 HttpPost post = new HttpPost(bidderUrl);
 post.setHeader("Content-Type", "application/json");    
 // I'm using http client with ThreadSafeClientConnManager
 // total conn = 500,  max conn per route = 100, timeout=500millis
 HttpClient httpClient = httpClientFactory.getHttpClient();
    try {
        post.setEntity(new StringEntity(jsobBidRequest));
        HttpResponse response = httpClient.execute(post);
        ...
    catch (NoHttpResponseException e){
        log.error(e);
    }

I'm running Jmetter with 50 concurrent threads (without a loop) and get a lot of exceptions like this:

org.apache.http.NoHttpResponseException The target server failed to respond 

While I'm running just 5 or 10 concurrent threads everything works ok.

Could you please advice me what could be wrong in my setup? For my understanding, I don't see any errors for the 50 concurrent thread requests.

Eliseo Ocampos
  • 2,473
  • 4
  • 20
  • 32
Julias
  • 5,752
  • 17
  • 59
  • 84

3 Answers3

54

I've found the root cause of the problem.

For some reason the connection becomes invalid and pool is not aware of it.

In this case the NoHttpResponseException is thrown and the request simply fails. I thought that such issues should be resolved in HTTP client pool layer and be transparent to my code, but this is not as it acts.

To solve this problem the HttpRequestRetryHandler in HTTP client should be overridden:

ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(schemeRegistry);
...
DefaultHttpClient httpClient = new DefaultHttpClient(cm, params);
httpClient.setHttpRequestRetryHandler(new HttpRequestRetryHandler() {
    @Override
    public boolean retryRequest(IOException exception, int executionCount, 
                                HttpContext context) {
        if (executionCount > 3) {
           LOGGER.warn("Maximum tries reached for client http pool ");
                return false;
        }
        if (exception instanceof org.apache.http.NoHttpResponseException) {
            LOGGER.warn("No response from server on " + executionCount + " call");
            return true;
        }
        return false;
      }
   }); 
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
Julias
  • 5,752
  • 17
  • 59
  • 84
  • 1
    Julias, this is very helpful! Thanks a lot for posting out your solution. It's exactly what i am looking for. – trillions Oct 10 '12 at 00:49
  • Your solution also helped me. In my case, the NoHttpResponseException only happened occasionally when I had the anti-virus activated. The anti-virus always run some scanning when a http request is sent, and occasionally takes a little longer, causing the request to fail. – Seigo Apr 23 '13 at 20:30
  • @Seigo - I understand this is an old thread, but did you have an executionTimeout because of which the requests were failing? What setting caused the requests to fail? – Andy Dufresne Feb 09 '15 at 12:21
  • @AndyDufresne, I was developing a desktop application for windows and some users' first requests always failed due to some verification made by the anti-virus. After adding the RetryHandler, my diagnosis was confirmed. It's been a long time and this is what I remember now, hope it helps. – Seigo Feb 23 '15 at 19:40
  • 10
    This solution worked for me, but imo you should rather use new StandardHttpRequestRetryHandler(3, true) insteadof your own implementation of the retry handler. The StandardHttpRequestRetryHandler does only retry those calls, for which the http method is idempotent – dknaus Apr 19 '16 at 13:36
  • Will this HttpRequestRetryHandler retry even if I'm getting any 4XX(401,403,404 etc.) response from the server? – iamdhavalparmar Jan 03 '23 at 14:20
12

This solution is for version HttpClient 4.5 and later. DefaultHttpClient is deprecated.

HttpClientBuilder clientBuilder = HttpClients.custom();
clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, false));
k_o_
  • 5,143
  • 1
  • 34
  • 43
5

I posted a comment in the defect logged at https://issues.apache.org/jira/browse/HTTPCLIENT-1610. As you can see, once I reduce the inactive http connection validate-before-reuse time from the default 2000 ms to something like 100 ms, I do not see any NoHttpResponseException any more.I have not tested to find out what is the threshold value in my environment to void using staled connection but 100 ms definitely is short enough in my environment.

user2363432
  • 51
  • 1
  • 1