如何用RabbitMQ实现可靠性?

时间:2018-03-06 12:35:23

标签: architecture rabbitmq amqp

我的数据存储在许多存储库中,我们期望一组任务(也就是作业)假设处理这些数据。每个作业都需要访问一个或两个数据存储库。对于大型文件,任务预计最多运行8小时,对于小文件,任务预计运行最少8毫秒。重要的是,作业只执行一次,不会错过。

我们需要设置更多在容器中运行的代理,以便它们执行任务。在启动时,每个代理都被授予对一组存储库的访问权限。每个代理应该只运行可以实现的作业。例如,分配一个需要访问" R1"的作业是没有意义的。和" R2"存储库只能访问" R2"," R3"," R4"和" R5"。

似乎RabbitMQ是这种情况的一个很好的候选者。但我觉得以下原因并不可靠:

  • 它可以两次发送相同的消息。
  • 可能会崩溃,因此邮件可能会丢失。
  • 某些代理商可能会在以后的某个时间开始工作,而这些工作可能会丢失。

我应该使用Redis避免两次处理相同的消息吗?

为了获得出色的可靠性,我应该运行一个不时重新填充队列的进程吗?

是"主题"交换一个好的解决方案,只将消息定向到可以处理它们的代理?如果是这样,如何处理在相应的代理开始之前发送消息的情况?

当然,如果您认为其他技术比AMQP更适合这项工作,请随时推荐它们。

1 个答案:

答案 0 :(得分:0)

让我们首先总结一下情况:

  • 您有任意数量的未知长度作业
  • 工作必须完成一次
  • 某些作业只能在某些机器上运行

从表面上看,这似乎是一个具有中等挑战性的job shop scheduling problem。但是,这不是你要问的。相反,您的问题似乎在于如何确保只处理一次作业,并且您正在寻找RabbitMQ来提供答案。

所以,让我们清楚一点。 RabbitMQ无法提供该答案,但也没有任何其他消息队列。这有两个原因:首先,消息队列不是作业,它是作业的保留位置。实际工作代表了系统中状态的变化。消息队列仅负责作业的交付,而不是作业的处理

其次,消息代理只能真正做出两种交付保证之一。虽然您可以使用at-most-once(通过auto-ack)和at-least-once(通过强制/立即标记)投放,these two options are mathematically mutually exclusive

外卖#1 很明显,在交付机制而不是处理机制中寻找解决方案是徒劳的。

但是,有一个解决方案。

幂等性是一个过程的属性,重复应用过程将导致相同的状态。无论系统处于开始阶段的状态如何,过程的输出都是相同的。一个简单的例子涉及一个灯开关。假设你告诉某人翻转一个灯开关100次,那个人就这样做了。即使假设你知道开关最初是关闭的,你能否在第100次翻转结束时对开关的状态做出任何保证?不 - 因为世界上没有任何东西是完全可靠的。

但是,假设您稍微调整一下,并说"将开关拨到向上位置。"现在,您有一个由命令产生的已定义的最终状态。在过程结束时,开关应该是#34; up"。多次接收此命令的人可以很容易地观察到开关的状态,并且如果开关已经处于正确状态,则不采取任何措施。

如果根据实现的结果来定义您的行为,而不是实现它的过程,那么您将更好地拥有幂等系统。因此,一个至少一次的交付机制,在RabbitMQ中很容易获得,将在100%的时间内为您服务。

外卖#2 根据结果而非流程定义您的行为。

最后一个问题是,如何做到这一点。有很多种方法,但这些方式都不是消息系统的状态容器。所有计算机系统都依赖某种持久存储机制(文件,数据库,穿孔卡?)来存储和检索系统状态。您应该依赖这些消息来提供以下信息:(1)需要做什么;(2)何时需要完成,而不是(3)需要如何完成。你必须通过在开始由消息触发工作之前检查当前状态来弄清楚#3。

外卖#3 不要将邮件队列用作状态容器。使用数据库。