实时抓取网页数据(SpiderDuck如何工作?Twitter的工程问题及解决方案)

优采云 发布时间: 2022-02-01 06:14

  实时抓取网页数据(SpiderDuck如何工作?Twitter的工程问题及解决方案)

  推文通常收录指向网络上各种内容的链接,包括图像、视频、新闻文章 和博客文章。SpiderDuck 是一项 Twitter 服务,它实时抓取这些链接,解析下载内容并提取有趣的元数据,并在几秒钟内将这些数据提供给其他 Twitter 服务。

  Twitter 的许多团队都需要访问链接的内容,尤其是要通过实时内容改进 Twitter 的产品。例如:

  背景

  在 SpiderDuck 之前,Twitter 有一项服务,通过发送 HEAD 请求和跟踪重定向来解析所有推文中的 URL。服务很简单,满足了当时公司的需求,但也有几个局限:

  显然,我们需要构建一个真正的 URL 抓取工具,能够克服上述限制并满足公司的长期目标。我们最初的想法是使用或构建一些开源抓取代码,但我们意识到几乎每个可用的开源抓取工具都有两个我们不需要的功能:

  因此,我们决定设计一个新系统来满足 Twitter 的实时需求,并随着它的发展而横向扩展。为了避免重新发明轮子,我们主要在开源模块上构建了新系统,以便我们可以继续利用开源社区的贡献。

  这是 Twitter 的典型工程问题——它们与其他大型互联网公司的问题类似,但要求一切都实时工作提出了独特而有趣的挑战。

  系统总览

  以下是 SpiderDuck 工作原理的概述。下图显示了它的主要组成部分。

  

  Kestrel:这是 Twitter 广泛使用的消息队列系统,用于对新推文进行排队。

  调度程序:这些工作单元决定是否抓取 URL、调度抓取时间和跟踪重定向跳转(如果有)。抓取后,它解析下载的内容,提取元数据,将元数据写回元数据存储,并将原创数据写入内容存储。每个调度器独立工作;也就是说,我们可以向系统添加任意数量的调度程序,随着推文和 URL 数量的增加,水平扩展系统。

  Fetcher:这些是 Thrift 服务器,用于维护短期 URL 获取队列,它们发送实际的 HTTP 获取请求并实现速率控制和处理 robots.txt。就像调度程序一样,它们可以随抓取速度水平扩展。

  Memcached:这是 fetcher 用来临时存储 robots.txt 文件的分布式缓存。

  Metadata Store:这是一个基于 Cassandra 的分布式哈希表,用于存储网页元数据和 URL 索引的解析信息,以及系统最近遇到的每个 URL 的爬取状态。该商店归 Twitter 所有,用于所有需要实时访问 URL 数据的客户服务。

  内容存储:这是一个 HDFS 集群,用于存储下载的内容和所有爬取信息。

  现在我们将详细介绍 SpiderDuck 的两个主要组件 - URL Scheduler 和 URLFetcher。

  网址调度程序

  下图描述了 SpiderDuck Scheduler 中的几个处理阶段。

  

  与大多数 SpiderDuck 一样,Scheduler 构建在由 Twitter 开发的名为 Finagle 的开源异步 RPC 框架之上。(实际上,这是最早使用 Finagle 的项目之一)。上图中的每个块,除了 KestrelReader 之外,都是一个 Finagle 过滤器 - 一种抽象,它允许将一系列处理阶段连接到一个完全异步的管道中。完全异步允许 SpiderDuck 使用少量、固定数量的线程来处理高流量。

  Kestrel Reader 会不断要求新的推文。当推文进入时,它们被发送到 TweetProcessor,它从中提取 URL。然后将每个 URL 发送到 Crawl Decider 阶段。此阶段从 MetadataStore 中读取 URL 的爬取状态,以确定 SpiderDuck 之前是否已看到该 URL。然后,Crawl Decider 根据预定义的爬取策略决定是否应该爬取 URL(也就是说,如果 SpiderDuck 在过去 X 天内看到了该 URL,则不再对其进行爬取)。如果 Decider 决定不抓取 URL,它会记录一个状态以指示处理已完成。如果它决定获取 URL,它将把 URL 发送到 Fetcher Client 阶段。

  Fetcher Client 阶段使用客户端库与 Fetcher 对话。客户端库实现逻辑来决定使用哪个 Fetcher 来获取 URL;它还可以处理重定向。(重定向跳转链很常见,因为 Twitter 帖子上的 URL 大多被缩短。)通过调度程序的每个 URL 都有一个关联的上下文对象。Fetcher 客户端将包括状态、下载的标头和内容在内的获取信息添加到上下文对象,并将其传递给后处理器。后处理器将下载的数据交给元数据提取器,后者检测页面的编码并使用开源 HTML5 解析器解析页面的内容。提取库实现了一系列启发式方法来提取元数据,例如标题、介绍和代表性图像。然后后处理器将所有元数据和抓取信息写入元数据存储。如果需要,后处理器还会安排一系列相关的提取。相关抓取的一个示例是嵌入的媒体内容,例如图像。

  在后处理之后,URL 上下文对象被传递到下一个阶段,该阶段使用一个名为 Scribe 的开源日志聚合器将所有信息(包括完整内容)记录在 ContentStore (HDFS) 日志中。此阶段还通知所有感兴趣的听众 URL 处理已完成。通知使用简单的发布者-订阅者模型,通过 Kestrel 的分散队列实现。

  所有处理阶段都是异步运行的——没有线程会等待一个阶段完成。与正在处理的每个 URL 关联的状态都存储在关联的上下文对象中,因此线程模型也非常简单。异步实现还受益于 Finagle 和 Twitter Util 库提供的方便的抽象和构造。

  网址提取器

  让我们看看 Fetcher 如何处理 URL。

  

  Fetcher 通过 Thrift 接口接收 URL。经过一些简单的确认后,Thrift 处理程序将 URL 传递给请求队列管理器,请求队列管理器将 URL 分配给适当的请求队列。计划任务将以固定速率从请求队列中读取。一旦从队列中取出 URL,它将被发送到 HTTPService 进行处理。基于 Finagle 构建的 HTTP 服务首先检查与 URL 关联的主机是否已经在缓存中。如果没有,那么它会为其创建一个 Finagle 客户端并安排对 robots.txt 文件的获取。下载 robots.txt 后,HTTP 服务会获取允许的 URL。robots.txt文件本身是缓存的,进程内Host Cache各一份,Memcached一份,防止每次有新的主机URL进来时重复爬取。

  一些名为 Vulture 的任务会定期检查 Request Queue 和 Host Cache 中是否有一段时间未使用的队列和主机;如果找到,它们将被删除。Vulture 还通过日志和 Twitter Commons 状态输出库报告有用的统计数据。

  Fetcher 的 Request Queue 还有一个重要的目标:速率限制。SpiderDuck 会限制对每个域名的 HTTP 抓取请求,以确保它不会使 Web 服务器过载。为了准确地限制速率,SpiderDuck 确保在任何时候每个 RequestQueue 都被分配给一个 Fetcher,并且在 Fetcher 失败时可以自动重新分配给另一个 Fetcher。一个名为 Pacemaker 的集群包将请求队列分配给 Fetcher 并管理故障转移。Fetcher 客户端库根据域名将 URL 分配给不同的请求队列。为整个网络设置的默认速率限制也可以根据需要被为特定域名设置的速率限制覆盖。也就是说,如果 URL 的进入速度超过了它们的处理速度,它们将拒绝告诉客户端它应该收敛的请求,

  为了安全起见,Fetcher 被部署在 Twitter 数据中心内的一个特殊区域 DMZ 中。这意味着 Fetcher 无法访问 Twitter 的产品群和服务。因此,确保它们是轻量级和自力更生是非常重要的,这是指导设计的许多方面的原则。

  Twitter 如何使用 SpiderDuck

  Twitter 服务以多种方式使用 SpiderDuck 的数据。大多数将直接查询元数据存储以获取 URL 的元数据(例如,标题)和解析信息(所有重定向后的最终标准化 URL)。元数据存储是实时填充的,通常在推文中发布 URL 的几秒钟内。这些服务不直接与 Cassandra 通信,而是通过代理这些请求的 Spiderduck Thrift 服务器。这个中间层为 SpiderDuck 提供了在需要时透明地切换存储系统的灵活性。它还支持比直接访问 Cassandra 更高级别的 API 抽象。

  其他服务会定期处理 SpiderDuck 在 HDFS 上的日志,以生成汇总统计信息,用于 Twitter 的内部测量仪表板或其他批处理分析。仪表板帮助我们回答诸如“每天在 Twitter 上分享多少张图片?”、“Twitter 用户最常链接到哪些新闻 网站?”之类的问题。和“昨天我们从某个 网站 上刮了多少?” 网页?”等等。

  需要注意的是,这些服务通常不会告诉 SpiderDuck 要抓取什么。SpiderDuck 已经抓取了所有访问 Twitter 的 URL。相反,这些服务会在 URL 可用后要求他们提供信息。SpiderDuck 还允许这些服务直接请求 Fetcher 通过 HTTP 获取任意内容(因此它们可以从我们的数据中心设置、速率限制、robot.txt 支持等中受益),但这种用法并不普遍。

  性能数据

  SpiderDuck 每秒处理数百个 URL。其中大部分在 SpiderDuck 获取策略定义的时间窗口内是唯一的,因此它们将被获取。对于抓取的 URL,SpiderDuck 的中位处理延迟低于 2 秒,其中 99% 的处理延迟低于 5 秒。延迟是根据推文发布时间来衡量的,即在用户点击“推文”按钮后的 5 秒内,推文中的 URL 被提取出来,准备爬取,并捕获所有重定向跳转。内容被下载和解析,元数据被提取,并且已经通过 MetadataStore 提供给客户。大部分时间要么花在 Fetcher 请求队列中(由于速率限制),要么实际从外部 Web 服务器获取 URL。

  SpiderDuck 基于 Cassandra 的元数据存储每秒可以处理近 10,000 个请求。这些请求通常针对单个或小批量(少于 20 个)的 URL,但它也可以处理大批量(200-300 个 URL)的请求。该存储系统的读取延迟中值约为 4 到 5 秒,第 99 个百分位范围约为 50 到 60 毫秒。

  谢谢

  SpiderDuck 的核心团队包括以下成员:Abhi Khune、Michael Busch、Paul Burstein、Raghavendra Prabhu、Tian Wang 和 YiZhuang。此外,我们要感谢公司中的以下人员,他们直接为该项目做出了贡献,帮助设置了 SpiderDuck 直接依赖的部分(例如 Cassandra、Finagle、Pacemaker 和 Scribe),或者帮助构建SpiderDuck 独特的数据中心设置:Alan Liang、Brady Catherman、Chris Goffinet、Dmitriy Ryaboy、Gilad Mishne、John Corwin、John Sirois、Jonathan Boulle、Jonathan Reichhold、Marius Eriksen、Nick Kallen、Ryan King、Samuel Luckenbill、Steve Jiang、Stu Hood和特拉维斯克劳福德。我们还要感谢整个 Twitter 搜索团队的宝贵设计反馈和支持。如果你也想参与这样的项目,

  原文地址::///2011/11/spiderduck-twitters-real-time-url.html

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线