다중 스레드 환경에서 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 라고 합니다. 자세한 내용은이 링크 를 참조 하십시오 ( "풀링 연결 관리자"로 스크롤). 예를 들면 :

    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/… ...? 내가 시도 할 때 때문에, 나는 ... diffrent 요청에서 세션을 유지 할 수 없습니다
sakthig

17
4.3.1 여기서 : PoolingClientConnManager는 PoolingHttpClientConnectionManager 대신 사용되지 않습니다.
Matthias

@DrewStephens 다시 PoolingClientConnManager는 PoolingHttpClientConnectionManager 찬성 deprecatd 한
didxga

18

httpclient 개발자 커뮤니티에서 방법 A를 권장합니다.

자세한 내용은 http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.html 을 참조하십시오.


1
클라이언트가 전역으로 설정되면 연결 관리자에서 언제 "종료"를 호출할까요?
Wand Maker

1
내부에서 ConnectionManager의 동작을 디버그하거나 "시각화"하는 데 유용한 도구 / 리눅스 명령은 무엇입니까? 현재 CLOSE_WAIT 및 기타 효과의 연결에 문제가 있으며 정확히 무슨 일이 일어나고 있는지 알 수있는 좋은 방법을 찾기 위해 노력하고 있기 때문에 묻습니다.
Christoph

@WandMaker 나는 프로그램이 종료되거나 한동안 연결이 필요하지 않은 일부 작업을 마쳤을 때 shutdown을 호출 할 것이라고 확신합니다.
Nicholas DiPiazza

1
@Christoph netstat는 정말 좋은 일을합니다. technet.microsoft.com/en-us/sysinternals/bb897437.aspx
Nicholas DiPiazza

13

문서를 읽은 것은 HttpConnection 자체가 스레드로부터 안전하지 않은 것으로 간주되므로 MultiThreadedHttpConnectionManager는 재사용 가능한 HttpConnections 풀을 제공하므로 모든 스레드에서 공유하고 정확히 한 번 초기화 된 단일 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로 HttpClient를 3.x를 4.x의에에서 마이그레이션 할 계획은 : 거의 ~ 2 년 내 응용 프로그램에서 완벽한 실행하지 있었다
Cheok 연의 쳉

9
물론, 누군가가 다른 :) 답변을 인터넷 검색 여기 온 단지 경우
토마스 Ahle

4

HttpClient 4.5를 사용하면 다음을 수행 할 수 있습니다.

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

이것은 연결 관리자를 종료하기 위해 Closeable을 구현합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.