【问题标题】:HttpClient multithread performanceHttpClient 多线程性能
【发布时间】:2013-10-16 16:11:52
【问题描述】:

我有一个应用程序,它使用HttpClient (4.1.3 or 4.2-beta) 从 62 个目标主机下载超过 4500 个 html 页面。它在 Windows 7 64 位上运行。处理器 - 酷睿 i7 2600K。网络带宽 - 54 Mb/s。

此时它使用这样的参数:

  • DefaultHttpClientPoolingClientConnectionManager
  • 还有IdleConnectionMonitorThread from
    http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html;
  • 最大总连接数 = 80;
  • 每条路由的默认最大连接数 = 5;
  • 对于线程管理,它使用具有并行性的ForkJoinPool
    level = 5(我是否正确理解它是一些工作
    线程?)

在这种情况下,我的网络使用率(在 Windows 任务管理器中)没有超过 2.5%。下载 4500 个页面需要 70 分钟。在 HttpClient 日志中我有这样的事情:

调试 ForkJoinPool-2-worker-1 [org.apache.http.impl.conn.PoolingClientConnectionManager]:连接 发布:[id:209][路由:{}->http://stackoverflow.com][保留总数 活着:6;分配的路线:5 条中的 1 条;总分配:80 个中的 10 个]

分配的连接总数不会超过 10-12,尽管我已将其设置为 80 个连接。 如果我尝试将并行度提高到 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())));
    }
}

问题是 - 使用多线程 HttpClient 的最佳做法是什么,可能有一些设置 ConnectionManagerHttpClient 的规则?如何使用全部 80 个连接并提高网络使用率?

如有需要,我会提供更多代码。

【问题讨论】:

    标签: java multithreading apache-httpclient-4.x


    【解决方案1】:

    我不确定您从多少个不同的主机中提取,但如果它是一个小数字(或只有 1 个),您希望增加每条路由的最大值。这将增加每个主机的并发性。

    目前您已将其设置为 5。您观察到最大连接使用量高达 10-12,也许您只访问 2-3 个不同的主机,在这种情况下,数学加起来。

    【讨论】:

      【解决方案2】:

      远程站点可以限制来自一个 IP 的并行连接数。事实上,这是一种很好的做法,因为许多爬虫实施得不好,会给服务器带来很大的负担。

      如果您抓取公共站点而不是您自己的站点,您至少应该尊重 robots.txt 并将您的请求限制为每个远程 IP 每秒一次。

      除此之外,每条路由(即 http://www.example.com/[whatever])的最大连接数为 5,因此您最多可以有 5 个并行连接到一个远程“地点”。 (路径被忽略,只是方案、主机和端口。)

      【讨论】:

        【解决方案3】:

        Apache HttpClient 绝对应该足够快,以使带宽饱和,即使是环回接口。我怀疑性能问题与内容处理的效率有关,而不是与内容检索的效率有关。您的应用程序只是花费更多时间处理 HTML 内容和提取链接,而不是下载新页面,从而导致带宽利用率不足。即使您的代码在处理之前将 HTML 内容转换为字符串这一事实也让我相信您的应用程序花费更多时间在内存中复制内容而不是通过网络传输数据。

        【讨论】:

        • 我已删除所有内容处理,但没有任何改变。这个问题会不会是和这个http://stackoverflow.com/questions/10673517/setmaxforroute-does-not-work-in-threadsafeclientconnmanager一样的东西引起的?
        • UPD:内容处理的 CPU 负载约为 0-1%。
        • @pepper:这毫无意义。如果您删除了内容处理,您的应用程序究竟如何提取链接以供后续提取?
        • @papper:无论如何,我认为你最好重新使用几个基于 HttpClient 的网络爬虫之一,然后尝试实现你自己的。
        • 我有一些(大约 60 个)RSS 提要,应用程序从中提取链接并提供给 ContentDownloader throw List&lt;Entry&gt; entries。所以我不需要递归地从内容中提取链接。唯一需要的是下载html页面。我是 Java 新手,您可以为这项任务推荐一个网络爬虫吗?
        猜你喜欢
        • 2014-08-10
        • 1970-01-01
        • 1970-01-01
        • 2012-09-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-21
        相关资源
        最近更新 更多