背着锄头的互联网农民

0%

【译】一个简单的搜索系统

本文翻译自Design a web crawler,主要描述了一个简单搜索系统的架构设计。

需求用例

基本需求
  • 抓取一系列的URLs的内容,生成倒排索引、标题和摘要。这里假设标题和摘要是静态的,不需要随着搜索词而动态改变。
  • 用户输入一个查询词,输出搜索到文章列表,每篇文章带有标题和摘要。
  • 系统具有高可用性
扩展需求
  • 搜索分析
  • 个性化搜索结果
  • Page rank

假设限制

状态假设
  • 具有热点问题,有些搜索词很热门
  • 仅支持匿名用户
  • 搜索耗时要非常短
  • 爬虫系统不能陷入死循环
  • 需要抓取10亿网页
    • 网页内容需要定期的更新
    • 一般网页平均更新周期为一个月一次,热门网页需要更频繁
      • 估算每个月大概需要抓取40亿网页
    • 每个页面平均大小为500KB
  • 每个月1000亿次查询
容量计算
  • 每个月需要存储2PB(500KB * 40亿)网页内容,3年需要存储72PB
  • 每秒1600次写请求
  • 每秒40000次查询

架构设计

爬虫系统

假设我们有一个初始的待抓取的URL列表links_to_crawl,其中的URL根据受欢迎程度排序。另外我们使用表crawled_links存储已抓取到的页面URL和其内容signature,这里可以使用kv-nosql数据库。对于待抓取列表links_to_crawl,我们可以存放到redis的zset中。接下来我们描述抓取的整个流程:

  • 从redis的zset中取优先级最高的URL,并抓取内容计算signature
    • 去crawled_links的数据库中查询相似的signature
      • 如果查找到有相似的signature,说明之前已经有抓取到相似的页面,这时候什么都不做。
      • 否则,
        • 添加一个任务到Reverse Index Service队列中用来生成倒排索引
        • 添加一个任务到Document Service队列中用来提取标题和摘要
        • 生成页面signature
        • 将该URL从links_to_crawl中删除
        • 将该URL和其内容signature加入到crawed_links数据库中
重复页面

为了保证抓取不会陷入死循环,我们使用signature的机制来防止重复抓取。signature的计算可以根据页面内容计算,通常的方法有Jaccard相似度或者Cos相似度。当然在计算之前,需要对页面内容进行分词、提取关键字等将页面转换为向量。

更新频率

一般来说,普通的页面每隔一周要重新抓取一遍以获得最新的内容,热门的网页需要更频繁一些。为了确认每个页面的更新频率,可以使用数据挖掘和统计分析的方式获得页面的更新频率,另外可以使用Robots.txt中建议的更新频率。

检索系统

  • 客户端发送http请求到Web服务器
  • Web服务器转发请求到Query Api服务,Query Api服务会做以下事情
    • 解析Query
    • 删除其中的标点符号
    • 修正拼写错误
    • 归一化大小写
  • Reverse Index倒排索引服务返回相关的文档
  • Document Service服务返回相关文档的标题和摘要

扩展架构

以下列了一些可能的优化措施:

  • 针对热门查询,可以使用内存缓存数据库,比如Redis、Memcache,减少系统的耗时,承接更大的流量。
  • Reverse Index服务和Document Index服务采用分布式系统
  • 域名解析可能会是瓶颈,需要自建DNS解析器并定期更新
  • 抓取系统使用连接池或者UDP来提升抓取性能
  • 保证带宽是足够用的