dream的小站 Resource Source Research Search

主从式分布式爬虫框架设计思路

一、假设一个海量数据爬取的环境

爬取数据时,我们一般都是从主页面进入,然后一层一层向下爬取,因此我们需要获取最初的“种子”url

  • 种子url1 Billion URL,假设在多层请求后,每个种子url里面还能链接到10个url, 一共10B URL
  • 假设每个网页大小100KB,一共有10B * 100KB ~ 10^12 KB ~ 1PB
  • 假设一个月需要爬所有网站,每天需要爬 10B/30days ~ 333M /day ~ 4K QPS

数据量大,QPS比较高,需要多台机器处理。这种情况下,内存无法容纳种子url,硬盘无法容纳网页大小,而带宽和cpu也不允许这么高的并发,我们就需要设计一个分布式爬虫

二、思考分布式爬虫的需求特点

首先思考一下,在设计分布式服务时,一般都有什么特点

面向海量数据的爬虫框架一般有以下几个需求:

  • 爬取任务量大,计算和io负载重
  • 不能反复重复抓取同一个网页
  • 不能出现单点故障影响整个系统的情况
  • 所需要的服务器资源应当是能够任意增加或缩减的

此外,爬虫一般不是直接面对用户,而是需要将数据推入数据库或消息队列,时间上也不需要同步返回数据,不需要强一致性

那也就意味着:

  • 高并发:服务需要分布式部署
  • 幂等:请求和爬取的数据都需要去重
  • 高可用:如果使用主从式架构,需要保证主节点可靠性
  • 高弹性:从节点可以任意上线下线,并保证下线或崩溃时数据不丢失
  • 最终一致性

三、爬虫的基本流程

一般来说,爬虫的数据爬取都有相似的流程

  1. 从数据库里面读取种子url
  2. 遍历url,开始下载html
  3. 对html内容进行解析
  4. 抽取到数据后转到5,抽取到url后将url加入数据库,跳转到1
  5. 数据做其他处理

以scrapy-redis为例,url数据库就是redis,在scrapy-redis中由Scheduler管理。

分析html页面,就是Spider模块,由用户自行管理

下载由Downloader管理

html内容的处理就是由Item和Pipeline处理,由用户自行管理

scrapy中有多种搜索算法

在绝大多数情况下,爬虫算法应该优先使用宽度优先搜索(bfs),这样可以防止在某个网站内一直爬浪费资源。

四、爬虫的具体实现

因此核心爬虫服务功能很简单,读取还没有被爬过的url,访问url下载html内容。

服务调度

为了能更快爬更多内容,爬虫服务应该越简单越好,不应该有处理逻辑,这样我们可以用便宜的机器大量纵向拓展。

爬虫服务爬完一个网页之后就把网页发到处理队列,让处理队列异步发送给html分析服务。发送的内容就是 url + html页面。 那么爬虫服务怎么获取url,是爬虫服务主动拉取url,还是url服务给爬虫服务发送url?

爬虫主动拉取url:好处是爬虫服务可以根据自己的负载去请求url,框架总体的负载较为均衡。坏处是服务端的查询负载很高

爬虫等待服务推送url: 实时性较高,同时推模式可以减少建立连接的开销,提高吞吐量。 这里我们可选择push模式。

请求队列

请求队列中需要储存url、请求的参数、请求体之类的东西,以分配给爬虫进行爬取,这里可以选用RabbitMQ,也可以选择redis

解析器
解析器是处理请求队列的消费者,负责对下载下来的内容进行解析

去重模块
当其收到一个url和网页的的时候。需要首先判断这个网页是否已经被爬过。

checksum:可以对收到的网页计算checksum,然后去网页数据库里找是否有相同的checksum。当然,这样也导致我们需要建立一个checksum的索引,这样才能方便我们找到checksum是否存在,如果使用16bytes的checksum,我们需要至少160GB内存。这个方法好处是精度高,坏处是消耗一些内存。

布隆过滤器:解析器也可以维护一个布隆过滤器,通过布隆过滤器来判断,好处是节省空间,我们只需要30g内存,坏处是可能会有精度问题,误判网页被抓取,导致漏爬。

判断完是否需要分析之后,分析服务可以开始分析网页,把网页中的url都提取出来,这些url都是潜在需要继续爬的对象,将这些url发送给url服务。

url服务
url服务是核心服务,它维持一个待抓取url的的队列。当它收到html分析服务发来的url的时候,首先先做出分析,判断url是否近期被爬过,这个可以直接和数据库里面的时间戳做对比。为了提高效率,我们同样可以把url相关信息放在缓存里面。

urlcache {
    string url;
    enum: status;
    long lastVistedTimestamp;
    long nextExecutionTime;
}

假设一条信息50Byte,10b个网页需要500G的内存空间,需要在多台机器上。然后url服务可以把收到的url进行排序,分组等操作,更合理地分配给爬虫服务

数据库

有一个URL数据库,存url相关的元数据,比如上一次被访问的时间等等。html数据库存网页blob。为了将url均分在所有分区,所有的数据可以根据url的哈希来分区,因为这里读和写的过程都可以有我们自己控制,并不存在冷热分区的问题。

死信队列
如果网站不能访问了怎么办?
爬失败了以后把url重新放回url服务的内存中,并设置好下次爬的时间。

DNS Resolver
对于大规模爬虫,一定要建立一个dns解析服务,让爬虫服务跟自己的dns解析服务通信,加快解析速度。

本页的评论功能已关闭