Thực hành tốt nhất để sử dụng HttpClient trong môi trường đa luồng


84

Trong một thời gian, tôi đã sử dụng HttpClient trong môi trường đa luồng. Đối với mỗi luồng, khi nó khởi tạo một kết nối, nó sẽ tạo một phiên bản HttpClient hoàn toàn mới.

Gần đây, tôi đã phát hiện ra rằng, bằng cách sử dụng cách tiếp cận này, nó có thể khiến người dùng mở quá nhiều cổng và hầu hết các kết nối đều ở trạng thái TIME_WAIT.

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

Do đó, thay vì mỗi chuỗi làm:

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

Chúng tôi dự định có:

[PHƯƠNG PHÁP A]

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

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

Trong tình huống bình thường, global_c sẽ được truy cập đồng thời bởi 50 ++ luồng. Tôi đã tự hỏi, liệu điều này có tạo ra bất kỳ vấn đề hiệu suất nào không? MultiThreadedHttpConnectionManager có đang sử dụng cơ chế không có khóa để thực hiện chính sách an toàn luồng của nó không?

Nếu 10 chủ đề đang sử dụng global_c thì 40 chủ đề còn lại có bị khóa không?

Hoặc sẽ tốt hơn nếu, trong mỗi luồng, tôi tạo một phiên bản của HttpClient, nhưng giải phóng trình quản lý kết nối một cách rõ ràng?

[PHƯƠNG PHÁP B]

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

Connman.shutdown () có gặp sự cố về hiệu suất không?

Tôi có thể biết phương pháp nào (A hoặc B) tốt hơn cho ứng dụng sử dụng luồng 50 ++ không?

Câu trả lời:


46

Chắc chắn là Phương pháp A vì nó được gộp chung và luồng an toàn.

Nếu bạn đang sử dụng httpclient 4.x, trình quản lý kết nối được gọi là ThreadSafeClientConnManager . Xem liên kết này để biết thêm chi tiết (cuộn xuống "Trình quản lý kết nối gộp"). Ví dụ:

    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 đã không được dùng nữa để thay thế cho PoolingClientConnManager trong 4.2
Drew Stephens

Xin chào, httpclient được tạo bằng phương pháp này có thể được sử dụng để duy trì phiên như được mô tả ở đây stackoverflow.com/questions/5960832/… ... không? Bởi vì khi tôi đã cố gắng, tôi đã không thể duy trì phiên qua các yêu cầu khác nhau ...
sakthig

17
4.3.1 tại đây: PoolingClientConnManager không được dùng nữa để thay thế cho PoolingHttpClientConnectionManager.
Matthias

@DrewStephens Again PoolingClientConnManager được deprecatd ủng hộ PoolingHttpClientConnectionManager
didxga

18

Phương pháp A được cộng đồng nhà phát triển httpclient khuyến nghị.

Vui lòng tham khảo http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.html để biết thêm chi tiết.


1
Khi nào sẽ có một cuộc gọi "tắt máy" trên trình quản lý kết nối nếu ứng dụng khách là toàn cầu.
Wand Maker

1
Những công cụ / lệnh linux nào hữu ích để gỡ lỗi hoặc "trực quan hóa" hành vi của ConnectionManager dưới mui xe? Tôi hỏi vì chúng tôi hiện đang gặp sự cố với các kết nối trong CLOSE_WAIT và các hiệu ứng khác và chúng tôi đang cố gắng tìm cách tốt để xem chính xác điều gì đang diễn ra.
Christoph

@WandMaker Tôi khá chắc chắn rằng bạn sẽ chỉ gọi tắt máy khi một trong hai chương trình thoát hoặc khi bạn hoàn thành một số công việc mà bạn sẽ không cần bất kỳ kết nối nào trong một thời gian.
Nicholas DiPiazza

1
@Christoph đã netstatlàm rất tốt điều đó. technet.microsoft.com/en-us/sysinternals/bb897437.aspx cũng vậy
Nicholas DiPiazza

13

Tôi đọc các tài liệu là bản thân HttpConnection không được coi là an toàn cho chuỗi và do đó MultiThreadedHttpConnectionManager cung cấp một nhóm HttpConnections có thể tái sử dụng, bạn có một MultiThreadedHttpConnectionManager được chia sẻ bởi tất cả các chuỗi và được khởi tạo chính xác một lần. Vì vậy, bạn cần một vài sàng lọc nhỏ cho tùy chọn A.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

Sau đó, mỗi luồng nên sử dụng trình tự cho mọi yêu cầu, nhận một hình nón từ nhóm và đặt nó trở lại khi hoàn thành công việc của mình - sử dụng một khối cuối cùng có thể tốt. Bạn cũng nên viết mã cho khả năng nhóm không có kết nối khả dụng và xử lý ngoại lệ thời gian chờ.

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

Khi bạn đang sử dụng một nhóm kết nối, bạn sẽ không thực sự đóng các kết nối và do đó, điều này sẽ không gây ra sự cố TIME_WAIT. Cách tiếp cận này giả định rằng mỗi luồng không bám vào kết nối lâu. Lưu ý rằng bản thân conman bị bỏ ngỏ.


Không thực sự trả lời cho câu hỏi của tôi, phương pháp nào (A hoặc B) tốt hơn.
Cheok Yan Cheng

5

Tôi nghĩ bạn sẽ muốn sử dụng ThreadSafeClientConnManager.

Bạn có thể xem cách nó hoạt động tại đây: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

Hoặc trong AndroidHttpClientđó sử dụng nó trong nội bộ.


1
Rất tiếc. Không có kế hoạch để di chuyển từ HttpClient 3.x để 4.x, như 3.x đã chạy hoàn hảo trong ứng dụng của tôi trong gần 2 năm ~ :)
Cheok Yan Cheng

9
Chắc chắn, chỉ cần nếu ai đó đến đây Googling cho một câu trả lời :)
Thomas Ahle

4

Với HttpClient 4.5 bạn có thể làm điều này:

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

Lưu ý rằng cái này thực hiện Closable (để tắt trình quản lý kết nối).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.