C# 尝试使用ZeroMQ构建分布式爬虫程序

C# 尝试使用ZeroMQ构建分布式爬虫程序,c#,php,zeromq,C#,Php,Zeromq,我刚开始学习ZeroMQ,并想在学习的同时构建一个分布式webcrawler作为示例 我的想法是有一个用PHP编写的“服务器”,它接受爬行应该从哪里开始的url worker(C#cli)必须抓取该url,提取链接,并将它们推回到服务器上的堆栈中。服务器不断将堆栈中的URL发送给工作者。 也许redis会跟踪所有已爬网的URL,因此我们不会多次爬网站点,并且能够提取当前进程的统计信息 我希望服务器能够平均分配任务,注意新的/缺少的工作人员,并在工作人员没有响应时重新分配URL 为什么服务器使用P

我刚开始学习ZeroMQ,并想在学习的同时构建一个分布式webcrawler作为示例

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

worker(C#cli)必须抓取该url,提取链接,并将它们推回到服务器上的堆栈中。服务器不断将堆栈中的URL发送给工作者。 也许redis会跟踪所有已爬网的URL,因此我们不会多次爬网站点,并且能够提取当前进程的统计信息

我希望服务器能够平均分配任务,注意新的/缺少的工作人员,并在工作人员没有响应时重新分配URL

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

为什么是C#为仆从:因为它在大多数windows机器上运行。我可以将可执行文件交给各种朋友,他们可以执行它并帮助我测试我的项目

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

我的第一种方法是推/拉模式,它通常适用于我的场景,但我不知道它的仆从。我认为我需要中间的经销商/路由器经纪人,并且必须处理我自己对工人的意识。 我发现了,但我不确定我是否理解答案

我想问一些关于如何弹劾zmq的提示。经销商的方法正确吗?有没有办法让员工自动意识到这一点?我想我需要一些资源/示例,或者你认为我只需要在zmq指南中深入挖掘

然而,一些关于正确方向的提示将非常有用:)


干杯

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

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

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)
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)
  }
为了解决您关于工人意识的问题,一种简单有效的方法使用FIFO堆栈和心跳消息;大概是这样的:

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)
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)
  }
  • 服务器在内存中维护一个简单的FIFO堆栈
  • 服务器发出心跳信号;爬虫用它们的节点名进行响应;路由器也会自动将节点的地址放入消息中(在消息中读取)
  • 将1个对象推送到包含节点名称和节点地址的堆栈上
  • 当服务器想要将工作分派给爬虫程序时,只需从堆栈中弹出下一个对象,创建消息并正确地指定地址(使用节点地址),然后关闭该工作程序
  • 以同样的方式向其他爬虫发送更多工作;当爬虫响应服务器时,只需将另一个具有节点名称/地址的对象推回到堆栈上;其他工人在他们做出回应之前都不能上班,所以我们不会打扰他们
这是一种简单但有效的基于工作人员可用性分配工作的方法,而不是盲目地发送工作。检查示例,概念是相同的

爬虫(工人) 工人应使用单个
经销商
插座和
子插座
DEALER
是异步通信的主套接字,子套接字订阅来自服务器的心跳消息。当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)
  }
剩下的你可以自己解决。通过例子,构建东西,打破它,构建更多,这是你学习的唯一方式


玩得开心,希望对你有帮助

你看过AsyncSvr的例子了吗?我一定跳过了,但看起来很有希望。稍后我会更深入地研究它。谢谢你,伙计!这是非常有用的。非常感谢你,朋友!回答得很好,令人鼓舞。