Get NoHttpResponseException для тестирования нагрузки
Я запускаю тесты нагрузки для своего приложения. У меня есть два сервера: один с моим приложением и фиктивный сервер, который отвечает за ответы.
В моем фиктивном сервере у меня есть следующий код jsp:
<%@ page import="java.util.Random" %>
<%@ page language="java" %>
<%@ page session="false" %>
<%
String retVal = "some json string";
Thread.sleep(50);
%>
Я запускаю приложение с tomcat7. Мой пул соединений server.xml(на обоих серверах) выглядит так:
<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" />
Код java, который я запускаю с серверов:
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);
}
Я запускаю Jmetter с 50 параллельными потоками (без цикла) и получаю много исключений вроде этого:
org.apache.http.NoHttpResponseException The target server failed to respond
Пока я запускаю только 5 или 10 одновременных потоков, все работает нормально.
Не могли бы вы посоветовать мне, что может быть неправильно в моей настройке? Насколько я понимаю, я не вижу ошибок для 50 параллельных запросов потока.
Ответы
Ответ 1
Я нашел основную причину проблемы.
По какой-то причине соединение становится недействительным, и пул не знает об этом.
В этом случае бросается NoHttpResponseException
, и запрос просто терпит неудачу. Я думал, что такие проблемы должны быть разрешены в пуле пула HTTP-клиентов и прозрачны для моего кода, но это не так, как он действует.
Чтобы решить эту проблему, клиент HttpRequestRetryHandler
в HTTP-клиенте должен быть переопределен:
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;
}
});
Ответ 2
Это решение для версии HttpClient 4.5 и более поздних версий. DefaultHttpClient устарел.
HttpClientBuilder clientBuilder = HttpClients.custom();
clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, false));
Ответ 3
Я отправил комментарий в дефект, зарегистрированный в https://issues.apache.org/jira/browse/HTTPCLIENT-1610. Как вы можете видеть, как только я уменьшаю неактивное время подключения HTTP до повторного использования с 2000 мс до 100 мс, я больше не вижу никакого исключения NoHttpResponseException. Я не тестировал, чтобы узнать, что такое пороговое значение в моей среде, чтобы аннулировать использование статического соединения, но 100 мс определенно достаточно коротким в моей среде.