2012-05-21 3 views
3

HttpClient (4.1.3 or 4.2-beta)을 사용하여 62 개의 대상 호스트에서 4500 개 이상의 html 페이지를 다운로드하는 응용 프로그램이 있습니다. 그것은 윈도우 7 64 비트에서 실행됩니다. 프로세서 - Core i7 2600K. 네트워크 대역폭 - 54 Mb/s. 이때HttpClient 멀티 스레드 성능

는 그러한 파라미터를 사용

  • DefaultHttpClientPoolingClientConnectionManager을하고;
  • 또한 IdleConnectionMonitorThread부터
    http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html까지입니다.
  • 최대 총 연결 = 80;
  • 경로 당 기본 최대 연결 수 = 5; 스레드 관리를 위해
  • 그것은 Windows 작업에 (병렬
    수준 = 5 (나는 그것이 작동
    스레드의 숫자 인 것을 올바르게 이해합니까?)

을이 경우 내 네트워크 사용과 ForkJoinPool를 사용 관리자) 2.5 % 이상 상승하지 않습니다. 4500 페이지를 다운로드하려면 70 분이 걸립니다.

DEBUG ForkJoinPool-2-노동자 1 [org.apache.http.impl.conn.PoolingClientConnectionManager] : 그리고 HttpClient를 로그에 나는 그런 일이 발표 연결 : [ID : 209] [경로 : {} -> http://stackoverflow.com] [총 보관 된 : 6; 할당 된 경로 : 1 of 5; 총 할당량 : 10 of 80]

총 할당 연결 수가 최대 80 개로 설정되었지만 할당 된 연결 수가 10-12 개를 초과하지 않습니다. 병렬 처리 수준을 20 또는 80으로 올리려고하면 네트워크 사용량은 동일하게 유지되지만 많은 연결 시간 제한이 생성됩니다.

hc.apache.org (HttpClient Performance Optimization GuideHttpClient Threading Guide)에 대한 튜토리얼을 읽었으나 도움이되지 않습니다.

public class ContentDownloader extends RecursiveAction { 
    private final HttpClient httpClient; 
    private final HttpContext context; 
    private List<Entry> entries; 

    public ContentDownloader(HttpClient httpClient, List<Entry> entries){ 
     this.httpClient = httpClient; 
     context = new BasicHttpContext(); 
     this.entries = entries; 
    } 

    private void computeDirectly(Entry entry){  
     final HttpGet get = new HttpGet(entry.getLink()); 
     try { 
      HttpResponse response = httpClient.execute(get, context); 
      int statusCode = response.getStatusLine().getStatusCode(); 

      if ((statusCode >= 400) && (statusCode <= 600)) { 
       logger.error("Couldn't get content from " + get.getURI().toString() + "\n" + response.toString()); 
      } else {   
       HttpEntity entity = response.getEntity(); 
       if (entity != null) { 
        String htmlContent = EntityUtils.toString(entity).trim(); 
        entry.setHtml(htmlContent); 
        EntityUtils.consumeQuietly(entity);        
       } 
      }       
     } catch (Exception e) { 
     } finally { 
      get.releaseConnection(); 
     } 
    } 

    @Override 
    protected void compute() { 
     if (entries.size() <= 1){   
      computeDirectly(entries.get(0)); 
      return;   
     }  
     int split = entries.size()/2;  
     invokeAll(new ContentDownloader(httpClient, entries.subList(0, split)), 
       new ContentDownloader(httpClient, entries.subList(split, entries.size()))); 
    } 
} 

을 그리고 질문은 - A는 ConnectionManagerHttpClient을 설정하는 몇 가지 규칙이있을 수 있습니다, 멀티 HttpClient 스레드 사용하는 가장 좋은 방법은 무엇입니까 :

작업의 코드는 다음과 같습니다? 어떻게 80 개의 모든 연결을 사용하고 네트워크 사용을 높일 수 있습니까?

필요한 경우 더 많은 코드를 제공합니다.

답변

0

Apache HttpClient는 루프백 인터페이스조차도 대역폭을 충분히 포화시킬만큼 빠르지 않아야합니다. 필자는 성능 문제가 콘텐츠 검색보다 콘텐츠 처리의 효율성과 관련이 있다고 생각합니다. 응용 프로그램은 새 페이지를 다운로드하는 것보다 HTML 컨텐트를 처리하고 링크를 추출하는 데 더 많은 시간을 소비하기 때문에 대역폭이 부족하게됩니다. 사실 코드를 처리하기 전에 HTML 콘텐트를 String으로 변환하더라도, 애플리케이션이 데이터를 전선으로 전송하는 것보다 메모리에 복사하는 데 더 많은 시간을 소비한다고 믿는다.

+0

콘텐츠 처리를 모두 제거했지만 변경된 사항은 없습니다. 이 문제는 이것과 동일한 문제로 발생할 수 있습니까? [http://stackoverflow.com/questions/10673517/setmaxforroute-does-not-work-in-threadsafeclientconnmanager](http://stackoverflow.com/questions/10673517/setmaxforroute -does-not-work-in-threadsafeclientconnmanager)? – peppered

+0

UPD : 콘텐츠 처리시 CPU로드가 약 0-1 %입니다. – peppered

+0

@pepper : 이것은 의미가 없습니다. 콘텐츠 처리를 제거한 경우 응용 프로그램은 이후의 가져 오기를 위해 어떻게 링크를 추출합니까? – oleg

4

내가 얼마나 많은 다른 호스트를 가져 왔는지 확신 할 수 없지만 숫자가 적거나 (또는 ​​단지 1 인 경우) 경로 당 최대 값을 늘리고 싶습니다. 이렇게하면 호스트 당 동시성이 높아집니다.

현재 5로 설정되어 있습니다. 최대 연결 사용량을 최대 10-12 회 관찰하는 경우 2-3 가지 호스트 만 공격 할 수 있습니다.이 경우 수학이 합산됩니다.

1

원격 사이트가 하나의 IP에서 병렬 연결 수를 제한 할 수 있습니다. 실제로 이것은 많은 크롤러가 잘못 구현되어 서버에 높은 부담을 초래하기 때문에 좋은 방법입니다.

robots.txt를 존중하고 개인 사이트가 아닌 공개 사이트를 크롤링하는 경우 원격 IP 당 초당 1 개로 제한해야합니다.

경로 당 최대 연결 수 (즉, http://www.example.com/[whatever))가 5 개이기 때문에 하나에 최대 5 개의 병렬 연결이있을 것으로 예상 할 수 있습니다 원격 "사이트". (경로는 무시되며 단지 구성표, 호스트 및 포트입니다.)