Best practice per utilizzare HttpClient in ambiente multithread


85

Per un po 'di tempo utilizzo HttpClient in un ambiente multithread. Per ogni thread, quando avvia una connessione, creerà un'istanza HttpClient completamente nuova.

Recentemente, ho scoperto che, utilizzando questo approccio, è possibile che l'utente abbia troppe porte aperte e la maggior parte delle connessioni sono nello stato TIME_WAIT.

http://www.opensubscriber.com/message/commons-httpclient-dev@jakarta.apache.org/86045.html

Quindi, invece di fare ogni thread:

HttpClient c = new HttpClient();
try {
    c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

Prevediamo di avere:

[METODO A]

// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());

try {
    global_c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

In una situazione normale, si accederà a global_c da 50 ++ thread contemporaneamente. Mi chiedevo, questo creerà problemi di prestazioni? MultiThreadedHttpConnectionManager utilizza un meccanismo senza blocchi per implementare la sua politica thread-safe?

Se 10 thread utilizzano global_c, gli altri 40 thread verranno bloccati?

O sarebbe meglio se, in ogni thread, creo un'istanza di un HttpClient, ma rilasci esplicitamente il gestore connessione?

[METODO B]

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
HttpClient c = new HttpClient(connman);
try {
      c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
    connman.shutdown();
}

Connman.shutdown () subirà problemi di prestazioni?

Posso sapere quale metodo (A o B) è migliore, per l'applicazione che utilizza un 50 ++ thread?

Risposte:


47

Sicuramente il metodo A perché è in pool e thread-safe.

Se stai usando httpclient 4.x, il gestore della connessione si chiama ThreadSafeClientConnManager . Vedi questo collegamento per ulteriori dettagli (scorri verso il basso fino a "Pooling connection manager"). Per esempio:

    HttpParams params = new BasicHttpParams();
    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry);
    HttpClient client = new DefaultHttpClient(cm, params);

49
ThreadSafeClientConnManager è stato deprecato a favore di PoolingClientConnManager in 4.2
Drew Stephens

Salve, il client http creato con questo metodo può essere utilizzato per mantenere la sessione come descritto qui stackoverflow.com/questions/5960832/… ...? Perché quando ho provato, non ero in grado di mantenere la sessione su richieste diverse ...
sakthig

17
4.3.1 qui: PoolingClientConnManager è stato deprecato a favore di PoolingHttpClientConnectionManager.
Matthias

@DrewStephens Again PoolingClientConnManager è stato ritirato a favore di PoolingHttpClientConnectionManager
didxga

18

Il metodo A è consigliato dalla comunità di sviluppatori httpclient.

Fare riferimento a http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.html per maggiori dettagli.


1
Quando si chiamerà "shutdown" su connection manager se il client è globale.
Wand Maker

1
Quali strumenti / comandi linux sono utili per eseguire il debug o "visualizzare" il comportamento del ConnectionManager dietro le quinte? Lo chiedo perché al momento abbiamo problemi con le connessioni in CLOSE_WAIT e altri effetti e ci stiamo sforzando di trovare un buon modo per vedere cosa sta succedendo esattamente.
Christoph

@WandMaker sono abbastanza sicuro che chiameresti shutdown quando uno dei programmi esce o quando hai finito con un lotto di lavoro in cui non avrai bisogno di connessioni per un po 'di tempo.
Nicholas DiPiazza

1
@Christoph netstatfa davvero un bel lavoro in questo. technet.microsoft.com/en-us/sysinternals/bb897437.aspx too
Nicholas DiPiazza

13

La mia lettura della documentazione è che HttpConnection stesso non viene trattato come thread safe, e quindi MultiThreadedHttpConnectionManager fornisce un pool riutilizzabile di HttpConnections, hai un singolo MultiThreadedHttpConnectionManager condiviso da tutti i thread e inizializzato esattamente una volta. Quindi hai bisogno di un paio di piccoli perfezionamenti per l'opzione A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

Quindi ogni thread dovrebbe usare la sequenza per ogni richiesta, ottenere una connessione dal pool e rimetterla a posto al termine del suo lavoro - usare un blocco finalmente può essere utile. È inoltre necessario codificare la possibilità che il pool non abbia connessioni disponibili ed elaborare l'eccezione di timeout.

HttpConnection connection = null
try {
    connection = connman.getConnectionWithTimeout(
                        HostConfiguration hostConfiguration, long timeout) 
    // work
} catch (/*etc*/) {/*etc*/} finally{
    if ( connection != null )
        connman.releaseConnection(connection);
}

Poiché stai utilizzando un pool di connessioni, in realtà non chiuderai le connessioni e quindi questo non dovrebbe incontrare il problema TIME_WAIT. Questo approccio presuppone che ogni thread non si blocchi a lungo sulla connessione. Nota che conman stesso viene lasciato aperto.


Non ha risposto effettivamente alla mia domanda, su quale metodo (A o B) è migliore.
Cheok Yan Cheng,


5

Con HttpClient 4.5 puoi fare questo:

CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();

Notare che questo implementa Closeable (per chiudere il gestore delle connessioni).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.