簡體   English   中英

HttpClient多線程性能

[英]HttpClient multithread performance

我有一個應用程序,使用HttpClient (4.1.3 or 4.2-beta)從62個目標主機下載超過4500個html頁面。 它運行在Windows 7 64位上。 處理器 - 酷睿i7 2600K。 網絡帶寬 - 54 Mb / s。

此時它使用這樣的參數:

  • DefaultHttpClientPoolingClientConnectionManager ;
  • 它也有IdleConnectionMonitorThread
    http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html ;
  • 最大總連接數= 80;
  • 每條路由的默認最大連接數= 5;
  • 對於線程管理,它使用ForkJoinPool和並行性
    level = 5(我是否理解正確,這是一些工作
    線程?)

在這種情況下,我的網絡使用率(在Windows任務管理器中)不會超過2.5%。 要下載4500頁,需要70分鍾。 在HttpClient日志中我有這樣的東西:

DEBUG ForkJoinPool-2-worker-1 [org.apache.http.impl.conn.PoolingClientConnectionManager]:已發布連接:[id:209] [route:{} - > http://stackoverflow.com] [保持活動狀態: 6; 分配的路線:1的5; 總分配:80的10]

分配的總連接數不會超過10-12,盡管我已將其設置為80個連接。 如果我嘗試將並行度級別提升到20或80,則網絡使用率保持不變,但會產生大量連接超時。

我已經閱讀了關於hc.apache.org的教程( HttpClient性能優化指南HttpClient線程指南 ),但它們沒有幫助。

任務的代碼如下所示:

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

問題是 - 使用多線程HttpClient的最佳做法是什么,可能有一些設置ConnectionManagerHttpClient規則? 如何使用所有80個連接並提高網絡使用率?

如有必要,我會提供更多代碼。

我不確定你有多少不同的主機,但如果它是一個小數字(或只是1),你想增加每條路線的最大值。 這將增加每個主機的並發性。

目前你將它設置為5.你正在觀察最多連接使用率高達10-12,也許你只打了2-3個不同的主機,在這種情況下,數學加起來。

遠程站點可以限制來自一個IP的並行連接數。 事實上,這是一種很好的做法,因為許多爬蟲實施得很糟糕,並且會給服務器帶來很大的負擔。

您至少應該尊重robots.txt並將您的請求限制為每個遠程IP每秒一個,如果您抓取一個公共站點而不是您自己的站點。

除此之外,每個路由的最大連接數(即http://www.example.com/ [whatever])為5,因此您可以預期最多有5個並行連接到一個遠程“站點” 。 (路徑被忽略,只是方案,主機和端口。)

Apache HttpClient肯定足夠快,甚至可以使環路帶寬飽和。 我懷疑性能問題與內容處理的效率有關,而不是內容檢索的效率。 您的應用程序只需花費更多時間處理HTML內容並提取鏈接,而不是下載新頁面,從而導致帶寬利用不足。 即使您的代碼在處理之前將HTML內容轉換為String這一事實也讓我相信您的應用程序花費更多時間在內存中復制內容而不是通過網絡傳輸數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM