分布式工作者的架构

我们正在创build一个能够跨多个地理位置分发任务的网站。 该网站应该能够:

  • 创build一个任务,
  • 把它放在队列中,
  • 根据地理标准将其分配给工作人员,
  • 根据工作状态更新网页界面(步骤1,2,3等),
  • 将最终结果保存在mongodb中并注意web界面。

只要他们不在相同的地理标准,我们就可以有平行的工作。

只要不处于处理状态,我们可以删除一个作业。

我们目前的堆栈是:Angulajs – nodejs – mongodb。

我们的第一个想法是从远程工作人员到MongoDB任务build立一个HTTP池。 重点是我们将有20多个遥远的工作人员,我们希望高频刷新(<1s)。 我们认为这个解决scheme很容易实现,但是很难维护和使数据库超载。 此解决scheme高度依赖于networkingping。

在networking上进行了一些研究之后,我们find了有关rabbitMQ和消息系统的文档。 这似乎符合我们的大部分要求,但是我看不到我们如何才能在待处理状态下删除队列中的特定作业,以及如何轻松处理任务状态的更新。

我们还find关于redis的文档,RAM中的KV系统。 这解决了这个问题,可以删除队列中的特定任务,并减lessmongodb的负载,但是我们没有看到我们如何能够注意到远方的工作人员在工作中做的事情。 如果是HTTP池,我们就失去了所有的好处。

我们的情况似乎是一个常见的问题,我想知道最好的解决scheme是什么?

这个架构很有趣,我想你可以使用RabbitMQ。

1.“创build任务”

你可以创build一个AMQP消息

2.“放在队列中”

你可以把它放到一个队列,或者更好的交换

3.根据地理标准将其分配给工作人员:

您可以使用铲子插件并使用路由键分配任务。 该插件是devise来容忍缓慢和地理networking。

4.根据工作状态更新网页界面(步骤1,2,3等)

这很容易,您可以使用web-socket将消息redirect到网页,也可以启用JavaScript web-STOMP插件“rabbitmq-plugins enable rabbitmq_web_stomp”,并直接使用它来更新页面。

5.在mongodb中保存最终结果并注意网页界面:

一旦得到消息,您可以将其保存到数据库。

唯一有点难的是删除一条消息,你可以在没有确认的情况下获得消息,然后将消息发送给你想要删除的消息。 无论如何,这不是一个正确的方式来使用RabbitMQ,我不知道你的环境,但你可以考虑使用TTL消息( http://www.rabbitmq.com/ttl.html )的过期消息。

为了更新一个任务,你不应该把消息更新到队列中,而是发送另一个带有“更新”信息的消息,然后你的应用程序应该在你的内部列表中更新任务状态。

我希望它可以是有用的。

Redis的

Redis非常棒,因为除了Job Queuing之外,还可以将其用于caching等其他function。 我个人使用Kue 。 跨数据中心的Kueing工作可能不是最好的决定。 虽然我不了解你的情况,但是一般都认为你的数据模型应该集中在你的内容被分发的地方。 我在San Fransisco运行一个托pipeAPI的服务,并在San Fran和NYC有CDN节点。 我的内容是服务器端模板,图像,脚本,CSS等,可以完全由我的API填充。

外包

如果你绝对需要这个function,我会亲自推荐iron.io。 他们提供2个服务,可能能够解决您的问题。 首先,他们通过一个RESTful API提供一个MQ系统,它非常易于使用,并且与节点完美协作。 也提供了一个工作者服务,它允许你排队,安排,并在他们的堆栈上运行任务。 如果您需要从自己的云中访问资源,这将是有限的,在这种情况下,我会推荐ironMQ。

内购

如果你不想外包你的服务,而你想承载一个MQ,我不会推荐rabbitMQ作为排队工作。 我会推荐一些更适合工作排队的 beanstalkd ,因为RabbitMQ更适合消息队列 (谁是垃圾 邮件 ?)。

另外:

阅读了一些其他答案的评论,在我看来,豆杆可能是你最好的办法。 它更加具体到工作排队,而许多其他MQ系统则是实时传递有关更新和推送新数据的信息,而且您必须在其上实现自己的Job Queuing系统。

Rabbit MQ,Redis和ZeroMQ很棒,但是你可以不用离开mongoDB。 有特殊的collections集命名封顶的集合 ,允许stream,他们都是非常快速和廉价的工作,为您的数据库。 您可以让您的工作人员(或其他进程)监听队列,然后执行任务。

例如,假设你有一个工作人员为每个地区,并说区域标有string。 然后,我们只需要创build一个内部队列来处理主逻辑中的更新。 我们将使用mongoose和asynchronous来显示它:

 var internalQueue = async.queue(function (doc, callback) { doc.status = 2; doc.save(function(e){ // We update the status of the task // And we follow from here, doing whatever we want to do }) }, 1); mongoose .TaskModel .find({ status: 1, region: "KH" // Unstarted stuff from Camboya }) .stream() .on('data', function (doc){ internalQueue.push(doc, function(e){ console.log('We have finished our task, alert the web interface or save me or something'); }); }); 

也许你不想使用mongoose或asynchronous,或者想要在每个地区使用geoqueries或多个worker,但是你可以使用你已有的工具:mongoDB和Node.js

要开始解决cap的集合,只需在mongoDBterminal上使用createCollection :

 db.createCollection('test', {capped: true, size: 100*1000, max: 100} ) 

只要记住两件事:

  1. 数据将基于插入顺序而不是时间或最后访问该文档,所以你的collections足够大。
  2. 您不能删除文档,但可以将其清空

如果我工作,我们正在使用亚马逊SQS ,我可以非常推荐给你。 这是便宜,可靠,规模和节省你很多麻烦(维护队列系统)。 我们在全球各个亚马逊地区都有工作人员。

对于节点有aws-sdk ,请看这里的文档

考虑到你的问题的范围,提供有用的build议是很困难的。 但是,如果是我,我可能会使用ZeroMQ ,我会使用一些像Router-Req的变体,我会保持队列和所有与服务器上的工作有关的数据,并处理我准备好的任务处理准备工作的工作人员,理解他们将立即开始接受任务,并且唯一需要反馈给服务器的数据已经完成。 如果您需要中止正在进行的工作,则可以使用第二对套接字进行控制通信,可能是Req-Rep配对。

套接字模式在相关的指南中有详细描述,在这里描述它们的工作要比我能用的更好,尽pipe这是一个重要的阅读。

通过重新使用EventEmitter API和STOMP代理,模块https://github.com/jkyberneees/distributed-eventemitter使分布式消息传递变得非常简单&#x3002; 当然,它会在你的消息架构上帮助你很多。