每秒几十万的大规模网络爬虫是如何炼成的?

【CSDN 编者按】数据时代,网络爬虫似乎是每个程序员的必备技能,在他们的眼中“一切皆可盘”。通常情况下,Python 凭借优秀的性能优势更受到程序员的喜爱,不过在本文中,作者介绍了他们公司一个强大的分布式网络爬虫驱动,由Java编写的系统能够每秒可以访问几十万个网页!

每秒几十万的大规模网络爬虫是如何炼成的?

作者 | Nariman Jelveh@Mixnode Technologies Inc.

译者 | 弯月

责编 | 郭芮

出品 | CSDN(ID:CSDNnews)

以下为译文:

我们公司Mixnode的背后由一个极其高效的分布式网络爬虫驱动,每秒可以访问几十万个网页。虽然在使用Mixnode时,你从来不需要考虑有关网络抓取的东西,但还是有很多人询问我们如何才能如此快速地抓取这么多网页。

在这篇文章中,我将与大家分享多年来我们在构建与优化爬虫方面所获得的经验以及教训。

Java

在为项目选择编程语言时,许多因素都会影响到你的最终决策。内部专业知识、生态系统和原始性能是我们在寻找“完美”的编程语言时必须考虑的主要标准。

最终,我们认为Java是我们的最佳选择,原因如下:

  • 内部专业知识:因为我们的团队拥有丰富的Java专业知识,特别是分布式系统和网络软件开发方面的知识,所以我们可以立即开始开发高质量的软件。
  • 现有的软件包:大规模的网络爬虫需要建立在久经考验的强大、可扩展且安全的网络、系统和实用程序模块之上。Java拥有最活跃的开源生态系统,特别是在网络和分布式应用程序方面。Netty、Selenium和Google Guava等软件包证明Java生态系统拥有高质量的开源模块。
  • 现有的参考项目:Apache Hadoop、Apache Cassandra和Elasticsearch全都是用Java开发的大型分布式系统项目的例子,它们为这个生态系统带来了丰富的专业知识、灵感和先例。当出现问题或有疑问时,通常我们都会发现曾有人经历过相同或类似的情况。这创建了一个强大的网络,从而使得用Java开发高性能数据驱动应用程序的过程变得更加简单且经济实惠。
  • 原始性能和可靠性:在性能和可靠性方面,Java拥有静态类型,强大的垃圾收集以及久经实战考验的虚拟机等最重要的特性。

虽然我们的核心网络爬虫引擎是用Java编写的,但在为手头的工作选择编程语言时我们都很务实。例如,我们也使用其他语言(例如Python,Perl和Node.js)来编写脚本、配置、监视、报告和管道的其他部分。

无共享架构

在Mixnode,我们的集群采用了无共享架构,工作负载在独立的无状态节点上进行分割和分布,这可以消除大规模分布式系统的灾难——单点故障。另外,该架构允许我们逐个节点更新和升级底层软件,而不会中断整个操作。

此外,无共享架构大大减少了节点之间的通信开销,从而为我们提供了额外的性能提升。

速率限制模块必须保证安全

网站的主要设计目的是供人类访问,一位普通用户每分钟只能浏览很少的页面。网络爬虫每秒能够访问数千甚至数百万个网页,因此,如果不小心,网络爬虫很容易在很短的时间内耗尽网站资源,造成破坏性的后果。而且,一个普通的网站会有多个机器人同时抓取,所以这个问题会被放大。

因此,每个网络爬虫也有责任对自己的请求速率进行限制,换句话说,确保连续两次访问之间有适当的延迟。你需要对请求速率进行限制的三个最重要的标准是:主机名和IP地址。

很显然,这项工作需要从一开始就做到尽善尽美。由于一个简单的错误就可能对你正在抓取的网站造成破坏性的后果,所以不容许出错。在多线程环境中,在跟踪请求和速率限制参数时,你还应该格外小心以防止竞争。

缓存是王道

在构建大规模数据驱动的应用程序时,缓存网络事务通常是不可避免的,至少在管道的某些部分如此,特别是当相较于其他任务网络输入/输出更频繁且开销更大的情况下。但是,在大规模网络爬取的情况下,缓存不仅是不可避免的,而且是在编写代码之前就需要考虑的事项。

大规模网络爬取的情况下,有两个操作需要及时缓存:

  • Robots.txt查找:从某个主机上访问的每个URL获取该主机robots.txt文件的全新副本几乎是不可能的,因此,你需要构建一个分布式的预读缓存,能够持有并定期更新数百万个网站的robots.txt文件。
  • DNS解析:对于绝大多数URL,你需要至少执行一次DNS解析才能下载,这会增加每秒数千次的查询。因此,DNS服务器必然会限制你的访问,或者在过重的负荷下崩溃。无论是哪种情况都会导致爬虫停止,唯一的解决办法就是尽可能缓存DNS解析结果,并最大限度地减少不必要的查询。

解析HTML

爬虫的基本任务之一就是从它访问的每个页面中提取链接(即解析),以便将它们添加到需要访问页面的队列中。如果你需要大规模的爬取,那么最好有一个高性能的HTML解析器,因为你需要提取大量的链接和元数据。

大多数HTML解析库会优先考虑简单性、易用性和通用性,一般来讲这是正确的设计。由于我们需要高速的链接提取,所以最终我们决定编写自己的解析器,并针对查找链接和一些原始DOM的查询功能进行了优化。

HTML解析器还需要具有弹性,经过全面的测试,并且能够处理大量出现的异常情况,因为并非每个HTML文档都是有效的。

网络优化

通常操作系统的默认配置无法处理大规模网络爬虫的网络需求。通常我们需要根据具体情况,优化操作系统的网络堆栈,使其发挥最大潜力。对于大规模的网络爬虫来说,优化的目标在于最大化吞吐量和打开连接的数量。

以下是我们经常会用到的有关该主题的一些有用的资源:

  • Linux网络性能参数
  • https://github.com/leandromoreira/linux-network-performance-parameters
  • 优化Web服务器,实现高吞吐量和低延迟
  • https://blogs.dropbox.com/tech/2017/09/optimizing-web-servers-for-high-throughput-and-low-latency/
  • Red Hat公司Linux网络性能调整指南
  • https://access.redhat.com/sites/default/files/attachments/20150325_network_performance_tuning.pdf

小结

构建大规模网络爬虫是一项长期的项目,也是一项复杂的工作。我们必须精心设计和测试不同的模块,同时还需仔细观测和研究权衡利弊。许多我们日常使用的计算机软件组件都无法在网络爬虫的工作负载下正常运行,因此我们需要从头开始设计,同时还需不断审查和优化其他组件,才能适应不断变化的不断扩大的网络。

我们的网络级爬虫经过了漫长的发展,才成为了成熟稳定的平台,我们期待分享更多关于学习构建基础架构的经验教训。

原文:https://www.mixnode.com/blog/posts/lessons-learned-building-a-modern-massive-scale-web-crawler

本文为 CSDN 翻译,如需转载,请注明来源出处。

相关推荐