J'exécute des tests de charge pour mon application. J'ai deux serveurs: un avec mon application et un serveur factice qui est chargé de m'obtenir des réponses.
Dans mon serveur factice, j'ai le code jsp suivant:
<%@ page import="Java.util.Random" %>
<%@ page language="Java" %>
<%@ page session="false" %>
<%
String retVal = "some json string";
Thread.sleep(50);
%>
J'exécute l'application avec Tomcat7. Mon pool de connexions server.xml (sur les deux serveurs) ressemble à:
<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" />
Le code Java Java que j'exécute à partir des serveurs est:
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);
}
J'utilise Jmetter avec 50 threads simultanés (sans boucle) et j'obtiens beaucoup d'exceptions comme ceci:
org.Apache.http.NoHttpResponseException The target server failed to respond
Pendant que je lance seulement 5 ou 10 threads simultanés, tout fonctionne bien.
Pourriez-vous s'il vous plaît me conseiller ce qui pourrait mal se passer dans ma configuration? Pour ma compréhension, je ne vois aucune erreur pour les 50 demandes de threads simultanées.
J'ai trouvé la cause première du problème.
Pour une raison quelconque, la connexion devient invalide et le pool n'en a pas connaissance.
Dans ce cas, le NoHttpResponseException
est levé et la requête échoue simplement. Je pensais que ces problèmes devraient être résolus dans la couche de pool de clients HTTP et être transparents pour mon code, mais ce n'est pas le cas.
Pour résoudre ce problème, le HttpRequestRetryHandler
dans le client HTTP doit être remplacé:
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;
}
});
Cette solution est pour la version HttpClient 4.5 et versions ultérieures. DefaultHttpClient est obsolète.
HttpClientBuilder clientBuilder = HttpClients.custom();
clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, false));
J'ai posté un commentaire dans le défaut enregistré à https://issues.Apache.org/jira/browse/HTTPCLIENT-161 . Comme vous pouvez le voir, une fois que j'ai réduit le temps de validation avant réutilisation de la connexion http inactif de 2000 ms par défaut à quelque chose comme 100 ms, je ne vois plus d'exception NoHttpResponseException.Je n'ai pas testé pour savoir quelle est la valeur de seuil dans mon environnement pour annuler en utilisant une connexion obsolète, mais 100 ms est certainement assez court dans mon environnement.