刚开始学习ZeroMQ,想在学习的同时搭建一个分布式网络爬虫为例。

我的想法是有一个用 PHP 编写的“服务器”,它接受一个应该开始爬行的 url。

Workers (C# cli) 必须抓取那个 url,提取链接,并将它们推回到服务器上的堆栈中。服务器不断向工作人员发送堆栈中的 url。
也许一个redis会跟踪所有爬取过的url,所以我们不会多次爬取站点,并且有能力提取当前进程的统计信息。

我想让服务器平均分配任务,注意新的/丢失的工作人员并在工作人员没有响应时重新分配 url。

为什么服务器使用 PHP:我对 PHP 非常满意,仅此而已。我不想让示例/测试项目更复杂。

为什么 C# 用于仆从:因为它可以在大多数 Windows 机器上运行。我可以将可执行文件提供给可以执行它并帮助我测试我的项目的各种 friend 。

爬行过程和 redis 功能不是我的问题的一部分。

我的第一种方法是 PUSH/PULL 模式,它通常适用于我的场景,但不知道它是 minions。我想我在中间需要一个经销商/路由器经纪人,并且必须自己处理 worker 的意识。

我找到了 this question 但我不确定我是否理解答案...

我在寻求一些提示如何阻止 zmq 的东西。经销商的做法是否正确?有什么方法可以自动获得 worker 意识?我想我需要一些资源/示例,还是您认为我只需要深入研究 zmq 指南?

但是,一些指向正确方向的提示会很棒:)

干杯

最佳答案

我正在构建一个工作/任务分配器,它的工作原理与您的爬虫相同,至少原则上是这样。以下是我学到的一些东西:

定义所有事件

服务器和爬虫之间的通信将基于系统中发生的不同事情,例如从服务器向爬虫分派(dispatch)工作,或者爬虫向服务器发送心跳消息。定义系统的事件类型;它们是用例:

DISPATCH_WORK_TO_CRAWLER_EVENT
CRAWLER_NODE_STATUS_EVENT
...

定义消息标准

服务器和爬虫之间的所有通信都应该使用 ZMsg 来完成,因此定义一个组织框架的标准,如下所示:
Frame1: "Crawler v1.0"             //this is a static header
Frame2: <event type>               //ex: "CRAWLER_NODE_STATUS_EVENT"
Frame3: <content xml/json/binary>  //content that applies to this event (if any)

现在您可以创建消息验证器来验证对等方之间收到的 ZMsgs,因为您有所有消息必须遵循的标准约定。

服务器

在服务器上使用单个 ROUTER 与爬虫进行异步和双向通信。此外,使用 PUB 套接字来广播心跳消息。

不要在 ROUTER 套接字上阻塞,使用 POLLER 每隔 5 秒循环一次,这允许服务器定期做其他事情,比如向爬虫广播心跳事件;像这样:
Socket rtr = .. //ZMQ.ROUTER
Socket pub = .. //ZMQ.PUB
ZMQ.Poller poller = new ZMQ.Poller(2)
poller.register( rtr, ZMQ.Poller.POLLIN)
poller.register( pub, ZMQ.Poller.POLLIN)

  while (true) {
     ZMsg msg = null
     poller.poll(5000)

     if( poller.pollin(0)){
        //messages from crawlers
        msg = ZMsg.recvMsg(rtr)
     }

     //send heartbeat messages
     ZMsg hearbeatMsg = ...
     //create message content here,
     //publish to all crawlers
     heartbeatMsg.send(pub)
  }

为了解决您关于 worker 意识的问题,一种简单而有效的方法使用 FIFO 堆栈和心跳消息;像这样:
  • 服务器在内存中维护一个简单的 FIFO 堆栈
  • 服务器发出心跳;爬虫用它们的节点名进行响应; ROUTER 也会自动将节点的地址放入消息中(读取消息 enveloping )
  • 将 1 个对象压入包含节点名称和节点地址的堆栈
  • 当服务器想要将工作分派(dispatch)给爬虫时,只需从堆栈中弹出下一个对象,创建消息和地址是正确的(使用节点地址),然后将其发送给该 worker
  • 以同样的方式将更多的工作分派(dispatch)给其他爬虫;当爬虫响应服务器时,只需将另一个具有节点名称/地址的对象推回堆栈;其他 worker 在他们回应之前不会有空,所以我们不会打扰他们。

  • 这是一种简单但有效的基于 worker 可用性分配工作的方法,而不是盲目地发送工作。查看 lbbroker.php 示例,概念是相同的。

    履带( worker )

    worker 应该使用一个 DEALER 套接字和一个 SUBDEALER 是异步通信的主要套接字,SUB 订阅来自服务器的心跳消息。当 worker 收到心跳消息时,它会在 DEALER 套接字上响应服务器。
    Socket dlr = .. //ZMQ.DEALER
    Socket sub = .. //ZMQ.SUB
    ZMQ.Poller poller = new ZMQ.Poller(2)
    poller.register( dlr, ZMQ.Poller.POLLIN)
    poller.register( sub, ZMQ.Poller.POLLIN)
    
      while (true) {
         ZMsg msg = null
         poller.poll(5000)
    
         if( poller.pollin(0)){
            //message from server
            msg = ZMsg.recvMsg(dlr)
         }
    
         if( poller.pollin(1)){
          //heartbeat message from server
           msg = ZMsg.recvMsg(sub)
           //reply back with status
           ZMsg statusMsg = ...
           statusMsg.send(dlr)
      }
    

    其余的你可以自己想办法。完成 PHP 示例、构建、破坏、构建更多内容,这是您学习的唯一方法!

    玩得开心,希望有帮助!

    关于c# - 尝试用 ZeroMQ 构建分布式爬虫,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19405005/

    10-11 06:41