分布式工作者的架构

时间:2014-03-25 13:42:59

标签: node.js redis rabbitmq

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

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

只要不符合相同的地理标准,我们就可以开展并行工作。

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

我们目前的筹码是:Angulajs - nodejs - mongodb。

我们的第一个想法是建立从远程工作者到mongodb任务的HTTP池。关键是我们将有超过20名远程工作人员,我们希望高频刷新(<1s)。我们认为这个解决方案易于实现,但很难维护并使DB过载。此解决方案高度依赖于网络ping。

经过网上的一些研究,我们找到了关于rabbitMQ和消息系统的文档。这似乎符合我们的大多数要求,但我不知道如何删除处于暂挂状态的队列中的特定作业以及我们如何轻松处理任务状态的更新。

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

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

6 个答案:

答案 0 :(得分:10)

Redis的

Redis非常棒,因为您可以将其用于除了作业排队之外的其他功能,例如缓存。我个人使用Kue。跨数据中心的Kueing工作可能不是最佳决策。虽然我不了解您的情况,但我们普遍认为您的数据模型应集中在您的内容分发的位置。我在San Fransisco运行一个托管API的服务,并在San Fran和NYC拥有CDN节点。我的内容是服务器端模板,图像,脚本,CSS等。可以通过我的API完全填充。

外包

如果您绝对需要此功能,我个人会推荐iron.io。他们提供2种服务,可以解决您的问题。首先,它们通过RESTful API提供MQ系统,它非常易于使用,并且与节点完美配合。它还提供了一个Worker服务,允许您在其堆栈上排队,计划和运行任务。如果您需要从您自己的云访问资源,这将是有限的,在这种情况下,我会推荐ironMQ。

Insource公司

如果您不想外包服务,并且想要托管MQ,我不建议使用rabbitMQ进行工作排队。我建议beanstalkd之类的内容更适合作业排队,其中RabbitMQ更适合消息排队(谁&#39; d咚?)。

此外:

在阅读了一些其他答案的评论之后,在我看来,beanstalkd可能是你最好的方法。它更适用于作业排队,而许多其他MQ系统会实时发送有关更新的消息并在您的云中推送新数据,并且您必须在此基础上实现自己的作业排队系统。 / p>

答案 1 :(得分:5)

Rabbit MQ,Redis和ZeroMQ非常棒,但你可以在不离开mongoDB的情况下完成它。有一些名为capped collections的特殊集合允许流式传输,它们对于数据库来说非常快速且便宜。您可以让您的工作人员(或其他进程)监听队列,然后执行任务。

例如,假设您为每个区域都有一名工作人员,并且所述区域都标有字符串。然后我们只需要创建一个内部队列来处理主逻辑中的更新。我们将使用mongooseasync来显示它:

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或async,或者想要在每个区域使用geoqueries或多个工作者,但是您可以使用已有的工具:mongoDB和Node。 JS

要开始使用上限集合,只需在mongoDB终端上使用createCollection

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

记住两件事:

  1. 数据将根据插入顺序而不是时间或对该文档的上次访问权限到期,因此您的馆藏足够大。
  2. 您无法移除文档,但只需将其清空
  3. 即可

答案 2 :(得分:3)

架构很有趣,我认为你可以使用RabbitMQ。

  

1.“创建任务”

您可以创建AMQP消息

  

2.“把它放在队列中”

你可以把它放到队列中,或者更好地交换到交换

  

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

您可以使用铲斗插件并使用路由键分配任务。该插件的设计允许缓慢的地理网络。

  

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

这很容易,您可以使用Web套接字将消息重定向到网页,或者您可以启用JavaScript web-STOMP插件“rabbitmq-plugins enable rabbitmq_web_stomp”,并直接使用它来更新页。

  

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

获取消息后,您可以将其保存到数据库中。

唯一有点困难的是它删除了一条消息,你可以在没有ack的情况下获取消息,然后将ack发送到你想删除的消息。 无论如何这不是使用RabbitMQ的正确方法,我不确切知道您的环境,但您可以考虑通过TTL消息(http://www.rabbitmq.com/ttl.html)使用过期消息。

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

我希望它有用。

答案 3 :(得分:2)

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

对于节点,有aws-sdk,请查看here以获取文档

答案 4 :(得分:1)

鉴于你的问题范围,很难给出有用的建议。但是,如果是我,我可能会使用ZeroMQ,我会使用一些变体,比如Router-Req,我会维护队列以及与工作相关的所有数据服务器,只是处理我准备好处理准备工作的工作人员的任务,并了解他们将在接收任务时立即开始工作,并且我需要反馈给服务器的唯一数据已完成工作。如果您需要能够中止正在进行的工作,可以使用第二对套接字进行控制通信,可能是Req-Rep配对。

套接字模式在链接指南中有完整的描述,它在描述它们方面要比我在这里有用得多,尽管它是一个重要的读物。

答案 5 :(得分:0)

模块https://github.com/jkyberneees/distributed-eventemitter通过重用EventEmitter API和STOMP代理使分布式消息传递变得非常简单。 当然,它可以为您的消息传递架构提供很多帮助。