5

各スレッドが対応する URL を 1 秒ごとにポーリングする 1000 個の専用 Java スレッドがあります。

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

スレッドは 1 秒ごとに実行されます。

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

問題は、ジョブを 1 秒ごとに実行すると、次のようなランダムな例外が発生することです。

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 

しかし、2 秒以上ごとにジョブを実行すると、すべて正常に実行されます。

shutDown() を使用して SimpleHttpConnectionManager() のインスタンスをシャットダウンしようとしましたが、効果はありませんでした。

netstat を実行すると、数千の TCP 接続が TIME_WAIT 状態にあることがわかります。これは、それらが閉じられており、クリアされていることを意味します。

したがって、接続数を制限するために、HttpClient の単一インスタンスを使用して、次のように使用してみました。

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

しかし、ちょうど 2 時間実行した後、「開いているファイルが多すぎます」というメッセージがスローされ始め、最終的には何もできなくなります。

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

許可される接続数を増やして機能させることができるはずですが、悪を長引かせるだけです。上記のような状況で HttpClient を使用するベストプラクティスは何ですか?

ところで、私はまだ HttpClient3.1 を使用しています。

4

3 に答える 3

3

これは数か月前に私たちに起こりました。最初に、毎回本当に releaseConnection() を呼び出していることを再確認してください。ただし、その場合でも、OS は実際に TCP 接続を一度にすべて再利用するわけではありません。解決策は、Apache HTTP クライアントのMultiThreadedHttpConnectionManagerを使用することです。これにより、接続がプールされ、再利用されます。

パフォーマンスに関するその他のヒントについては、 http://hc.apache.org/httpclient-3.x/performance.htmlを参照してください。

更新: おっと、下のコード サンプルを読んでいませんでした。releaseConnection() を実行し、MultiThreadedHttpConnectionManager を使用している場合は、プロセスごとに開いているファイルに対する OS の制限が十分に高く設定されているかどうかを検討してください。私たちにもその問題があり、制限を少し拡張する必要がありました。

于 2010-05-26T15:28:17.473 に答える
2

最初のエラーは問題ありません。利用可能な経験的ポートを使い果たしました。各 TCP 接続は、2 分間 TIME_WAIT 状態に留まることができます。2000/秒を生成します。遅かれ早かれ、ソケットは未使用のローカル ポートを見つけることができず、そのエラーが発生します。TIME_WAIT はまさにこの目的のために設計されています。これがないと、システムが以前の接続をハイジャックする可能性があります。

2 番目のエラーは、開いているソケットが多すぎることを意味します。一部のシステムでは、1K のオープン ファイルの制限があります。ソケットやその他の開いているファイルが残っているために、その制限に達しただけかもしれません。Linux では、次を使用してこの制限を変更できます。

  ulimit -n 2048

しかし、それはシステム全体の最大値によって制限されています。

于 2010-05-26T15:25:52.637 に答える
0

sudo または root として /etc/security/limits.conf ファイルを編集します。「# End of File」のすぐ上にあるファイルの終わりに、次の値を入力します。 * soft nofile 65535 * hard nofile 65535 これにより、開いているファイルの数が無制限に設定されます。

于 2012-08-20T08:48:42.853 に答える