Ho 1000 thread Java dedicati in cui ogni thread esegue il polling di un url corrispondente ogni secondo.BindException/Troppi file aperti durante l'utilizzo di HttpClient sotto carico
public class Poller {
public static Node poll(Node node) {
GetMethod method = null;
try {
HttpClient client = new HttpClient(new SimpleHttpConnectionManager(true));
......
} catch (IOException ex) {
ex.printStackTrace();
} finally {
method.releaseConnection();
}
}
}
I fili gestiscono ogni secondo:
for (int i=0; i <1000; i++) {
MyThread thread = threads.get(i) // threads is a static field
if(thread.isAlive()) {
// If the previous thread is still running, let it run.
} else {
thread.start();
}
}
Il problema è se corro il lavoro ogni secondo ottengo eccezioni casuali come questi:
java.net.BindException: Address already in use
INFO httpclient.HttpMethodDirector: I/O exception (java.net.BindException) caught when processing request: Address already in use
INFO httpclient.HttpMethodDirector: Retrying request
Ma se io eseguire il lavoro ogni 2 secondi o più, tutto funziona correttamente.
Ho anche provato a chiudere l'istanza di SimpleHttpConnectionManager() usando shutDown() senza alcun effetto.
Se eseguo netstat, vedo migliaia di connessioni TCP nello stato TIME_WAIT, il che significa che sono state chiuse e si stanno cancellando.
Quindi, per limitare il no di connessioni, ho provato ad utilizzare una singola istanza di HttpClient e usarlo in questo modo:
public class MyHttpClientFactory {
private static MyHttpClientFactory instance = new HttpClientFactory();
private MultiThreadedHttpConnectionManager connectionManager;
private HttpClient client;
private HttpClientFactory() {
init();
}
public static HttpClientFactory getInstance() {
return instance;
}
public void init() {
connectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams managerParams = new HttpConnectionManagerParams();
managerParams.setMaxTotalConnections(1000);
connectionManager.setParams(managerParams);
client = new HttpClient(connectionManager);
}
public HttpClient getHttpClient() {
if (client != null) {
return client;
} else {
init();
return client;
}
}
}
Tuttavia dopo l'esecuzione per esattamente 2 ore, inizia gettando 'troppi file aperti' e alla fine non può fare nulla.
ERROR java.net.SocketException: Too many open files
INFO httpclient.HttpMethodDirector: I/O exception (java.net.SocketException) caught when processing request: Too many open files
INFO httpclient.HttpMethodDirector: Retrying request
dovrei essere in grado di aumentare il no di connessioni consentite e farlo funzionare, ma mi sarebbe solo prolungare il male. Qualche idea su quale sia la migliore pratica per usare HttpClient in una situazione come quella precedente?
Btw, sono ancora su HttpClient3.1.
@Langali: Oh duh, questo mi insegnerà a leggere un post completamente! Un'altra cosa da considerare è se il limite del sistema operativo sul numero di file aperti per processo è forse impostato un po 'troppo basso. Abbiamo esteso la nostra quando abbiamo scoperto che Glassfish utilizzava quasi tutto il suo lotto per eseguire il caricamento delle classi, ecc. Abbiamo risolto il problema per noi. –