マルチスレッド環境でHttpClientを使用するためのベストプラクティス


84

しばらくの間、私はマルチスレッド環境でHttpClientを使用してきました。すべてのスレッドについて、接続を開始すると、完全に新しいHttpClientインスタンスが作成されます。

最近、このアプローチを使用すると、ユーザーが開いているポートが多すぎて、ほとんどの接続がTIME_WAIT状態になる可能性があることを発見しました。

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

したがって、各スレッドの代わりに:

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

私たちは持っている予定です:

[方法A]

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

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

通常の状況では、global_cは50 ++スレッドによって同時にアクセスされます。私は疑問に思っていました、これはパフォーマンスの問題を引き起こしますか?MultiThreadedHttpConnectionManagerは、ロックフリーメカニズムを使用してスレッドセーフポリシーを実装していますか?

10個のスレッドがglobal_cを使用している場合、他の40個のスレッドはロックされますか?

または、すべてのスレッドでHttpClientのインスタンスを作成し、接続マネージャーを明示的に解放するとよいでしょうか。

[方法B]

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

connman.shutdown()はパフォーマンスの問題を抱えていますか?

50 ++スレッドを使用するアプリケーションには、どちらの方法(AまたはB)が適しているかわかりますか?

回答:


46

プールされてスレッドセーフであるため、間違いなく方法Aです。

httpclient 4.xを使用している場合、接続マネージャーはThreadSafeClientConnManagerと呼ばれます。詳細については、このリンクを参照してください(「Poolingconnectionmanager」までスクロールダウンします)。例えば:

    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は、4.2でPoolingClientConnManagerを優先して非推奨になりました
Drew Stephens

こんにちは、このメソッドによって作成されたhttpclientは、ここで説明されているようにセッションを維持するために使用できますかstackoverflow.com/questions/5960832/… ...?試したところ、
異なる

17
4.3.1ここ:PoolingClientConnManagerは非推奨になり、PoolingHttpClientConnectionManagerが優先されます。
マティアス

@DrewStephens再びPoolingClientConnManagerは廃止され、PoolingHttpClientConnectionManagerが優先されました
didxga

18

方法Aは、httpclient開発者コミュニティによって推奨されています。

詳細については、http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.htmlを参照してください。


1
クライアントがグローバルになっている場合、接続マネージャで「シャットダウン」を呼び出すのはいつですか。
ワンドメーカー

1
内部でConnectionManagerの動作をデバッグまたは「視覚化」するのに役立つツール/ Linuxコマンドはどれですか?現在、CLOSE_WAITの接続やその他の効果に問題があり、正確に何が起こっているのかを確認するための良い方法を見つけるのに苦労しているので、私は尋ねます。
クリストフ

@WandMakerプログラムが終了したとき、またはしばらくの間接続が不要な作業のバッチが終了したときに、shutdownを呼び出すだけだと確信しています。
ニコラスディピアッツァ2017

1
@Christophnetstatはそれで本当に素晴らしい仕事をしています。technet.microsoft.com/en-us/sysinternals/bb897437.aspx
Nicholas DiPiazza 2017

13

私がドキュメントを読んだところ、HttpConnection自体はスレッドセーフとして扱われないため、MultiThreadedHttpConnectionManagerは再利用可能なHttpConnectionsのプールを提供し、すべてのスレッドで共有され、1回だけ初期化される単一のMultiThreadedHttpConnectionManagerがあります。したがって、オプションAにいくつかの小さな改良が必要です。

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

次に、各スレッドはすべてのリクエストにシーケンスを使用し、プールから接続を取得して、作業の完了時に元に戻す必要があります。finallyブロックを使用するとよい場合があります。また、プールに使用可能な接続がない可能性をコーディングして、タイムアウト例外を処理する必要があります。

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

接続のプールを使用しているため、実際には接続を閉じることはないため、これによってTIME_WAITの問題が発生することはありません。このアプローチは、各スレッドが接続に長時間ハングアップしないことを前提としています。conman自体は開いたままであることに注意してください。


どちらの方法(AまたはB)が優れているか、私の質問に対する実際の回答はありませんでした。
Cheok Yan Cheng

5

ThreadSafeClientConnManagerを使用することをお勧めします。

あなたはそれがどのように機能するかをここで見ることができます:http//foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

またはAndroidHttpClient内部でそれを使用するで。


1
Opps。3.xは私のアプリケーションでほぼ2年間完璧に実行されていたため、HttpClient 3.xから4.xに移行する予定はありません:)
Cheok Yan Cheng 2010

9
確かに、誰か他の人がここに来て答えを求めてグーグルで来たとしても:)
Thomas Ahle 2010

4

HttpClient 4.5を使用すると、次のことができます。

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

これはCloseable(接続マネージャーのシャットダウン用)を実装していることに注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.