如何在抓取大量小文件时调整HTTPClient性能?

时间:2016-09-19 14:39:00

标签: java web-crawler httpclient

我只想抓一些黑客新闻故事和我的代码:

import org.apache.http.client.fluent.Request;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Logger;
import java.util.stream.IntStream;

public class HackCrawler {
    private static String getUrlResponse(String url) throws IOException {
        return Request.Get(url).execute().returnContent().asString();
    }

    private static String crawlItem(int id) {
        try {
            String json = getUrlResponse(String.format("https://hacker-news.firebaseio.com/v0/item/%d.json", id));
            if (json.contains("\"type\":\"story\"")) {
                return json;
            }
        } catch (IOException e) {
            System.out.println("crawl " + id + " failed");
        }
        return "";
    }

    public static void main(String[] args) throws FileNotFoundException {
        Logger logger = Logger.getLogger("main");
        PrintWriter printWriter = new PrintWriter("hack.json");
        for (int i = 0; i < 10000; i++) {
            logger.info("batch " + i);
            IntStream.range(12530671 - (i + 1) * 100, 12530671 - i * 100)
                    .parallel()
                    .mapToObj(HackCrawler::crawlItem).filter(x -> !x.equals(""))
                    .forEach(printWriter::println);
        }
    }
}

现在抓取100(1批)物品需要3秒钟。

我发现parallel使用多线程会加速(大约5次),但我不知道如何进一步优化它。

有人可以提出一些建议吗?

2 个答案:

答案 0 :(得分:1)

要实现Fayaz意味着我将使用Jetty Http Client异步功能(https://webtide.com/the-new-jetty-9-http-client/)。

httpClient.newRequest("http://domain.com/path")
        .send(new Response.CompleteListener()
        {
            @Override
            public void onComplete(Result result)
            {
                // Your logic here
            }
        });

此客户端在内部使用Java NIO来监听每个连接使用单个线程的传入响应。然后,它将内容分派给不涉及任何阻塞I / O操作的工作线程。

您可以尝试使用每个目的地的最大连接数(目的地基本上是主机)

http://download.eclipse.org/jetty/9.3.11.v20160721/apidocs/org/eclipse/jetty/client/HttpClient.html#setMaxConnectionsPerDestination-int-

由于您正在大量加载单个服务器,因此这应该非常高。

答案 1 :(得分:0)

以下步骤可帮助您入门。

  1. 使用单个线程从站点获取响应,因为这基本上是一个IO操作。
  2. 将这些响应放入队列中(了解BlockingQueue的各种实现)
  3. 现在,您可以拥有多个线程来获取这些响应并按照您的意愿处理它们。
  4. 基本上,您将拥有一个生产者线程,可以从网站和处理这些响应的多个消费者那里获得响应。