Best Practice für die Verwendung von HttpClient in Multithread-Umgebungen

83

Seit einiger Zeit verwende ich HttpClient in einer Multithread-Umgebung. Wenn für jeden Thread eine Verbindung hergestellt wird, wird eine vollständig neue HttpClient-Instanz erstellt.

Kürzlich habe ich festgestellt, dass bei Verwendung dieses Ansatzes der Benutzer möglicherweise zu viele Ports geöffnet hat und sich die meisten Verbindungen im Status TIME_WAIT befinden.

http://www.opensubscriber.com/message/[email protected]/86045.html

Daher, anstatt dass jeder Thread Folgendes tut:

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

Wir planen:

[Methode A]

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

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

In einer normalen Situation wird von 50 ++ Threads gleichzeitig auf global_c zugegriffen. Ich habe mich gefragt, ob dies zu Leistungsproblemen führt. Verwendet MultiThreadedHttpConnectionManager einen sperrfreien Mechanismus, um seine thread-sichere Richtlinie zu implementieren?

Wenn 10 Threads global_c verwenden, werden die anderen 40 Threads gesperrt?

Oder wäre es besser, wenn ich in jedem Thread eine Instanz eines HttpClient erstelle, aber den Verbindungsmanager explizit freigebe?

[Methode B]

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

Wird connman.shutdown () Leistungsprobleme haben?

Darf ich wissen, welche Methode (A oder B) für die Anwendung mit 50 ++ Threads besser ist?

Cheok Yan Cheng
quelle

Antworten:

45

Auf jeden Fall Methode A, weil sie gepoolt und threadsicher ist.

Wenn Sie httpclient 4.x verwenden, heißt der Verbindungsmanager ThreadSafeClientConnManager . Weitere Informationen finden Sie unter diesem Link (scrollen Sie nach unten zu "Pooling Connection Manager"). Beispielsweise:

    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);

quelle
49
ThreadSafeClientConnManager wurde zugunsten von PoolingClientConnManager in 4.2
Drew Stephens
Hallo, kann der mit dieser Methode erstellte httpclient verwendet werden, um die Sitzung wie hier beschrieben zu verwalten. Stackoverflow.com/questions/5960832/… ...? Denn als ich es versuchte, war ich nicht in der Lage, die Sitzung über verschiedene Anfragen hinweg aufrechtzuerhalten ...
sakthig
17
4.3.1 hier: PoolingClientConnManager wurde zugunsten von PoolingHttpClientConnectionManager veraltet.
Matthias
@DrewStephens Again PoolingClientConnManager wurde zugunsten von PoolingHttpClientConnectionManager
didxga
18

Methode A wird von der httpclient-Entwicklergemeinde empfohlen.

Weitere Informationen finden Sie unter http://www.mail-archive.com/[email protected]/msg02455.html .

Cheok Yan Cheng
quelle
1
Wann wird im Verbindungsmanager "shutdown" aufgerufen, wenn der Client global ist?
Zauberstabmacher
1
Welche Tools / Linux-Befehle sind nützlich, um das Verhalten des ConnectionManager unter der Haube zu debuggen oder zu "visualisieren"? Ich frage, weil wir derzeit Probleme mit Verbindungen in CLOSE_WAIT und anderen Effekten haben und Schwierigkeiten haben, einen guten Weg zu finden, um zu sehen, was genau los ist.
Christoph
@WandMaker Ich bin mir ziemlich sicher, dass Sie Shutdown nur aufrufen würden, wenn entweder das Programm beendet wird oder wenn Sie mit einer Reihe von Arbeiten fertig sind, bei denen Sie für einige Zeit keine Verbindungen benötigen.
Nicholas DiPiazza
1
@Christoph netstatmacht einen wirklich guten Job. technet.microsoft.com/en-us/sysinternals/bb897437.aspx auch
Nicholas DiPiazza
13

Ich habe in den Dokumenten gelesen, dass HttpConnection selbst nicht als threadsicher behandelt wird. Daher bietet MultiThreadedHttpConnectionManager einen wiederverwendbaren Pool von HttpConnections. Sie haben einen einzelnen MultiThreadedHttpConnectionManager, der von allen Threads gemeinsam genutzt und genau einmal initialisiert wird. Sie benötigen also ein paar kleine Verbesserungen an Option A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

Dann sollte jeder Thread die Sequenz für jede Anforderung verwenden, eine Verbindung aus dem Pool abrufen und sie nach Abschluss seiner Arbeit wieder zurücksetzen - die Verwendung eines finally-Blocks kann gut sein. Sie sollten auch die Möglichkeit codieren, dass für den Pool keine Verbindungen verfügbar sind, und die Timeout-Ausnahme verarbeiten.

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

Da Sie einen Pool von Verbindungen verwenden, werden die Verbindungen nicht geschlossen, sodass das Problem TIME_WAIT nicht auftreten sollte. Dieser Ansatz setzt voraus, dass nicht jeder Thread lange an der Verbindung festhält. Beachten Sie, dass Conman selbst offen bleibt.

djna
quelle
Ich habe meine Frage nicht beantwortet, welche Methode (A oder B) besser ist.
Cheok Yan Cheng
5

Ich denke, Sie werden ThreadSafeClientConnManager verwenden wollen.

Sie können hier sehen, wie es funktioniert: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

Oder in der, AndroidHttpClientdie es intern verwendet.

Thomas Ahle
quelle
1
Opps. Kein Plan, von HttpClient 3.x auf 4.x zu migrieren, da 3.x in meiner Anwendung seit fast ~ 2 Jahren fehlerfrei läuft :)
Cheok Yan Cheng
9
Sicher, nur wenn jemand anderes hierher gekommen ist, um eine Antwort zu googeln :)
Thomas Ahle
4

Mit HttpClient 4.5 können Sie dies tun:

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

Beachten Sie, dass dieser Closeable implementiert (zum Herunterfahren des Verbindungsmanagers).

Dimitar II
quelle