3

我目前正在重新设计一个系统并且遇到了一些麻烦。

要求

我有一个消息队列(一个RabbitMQ队列)和一些从该队列消耗的服务。每条消息都有一个 id 表示它是一个组的一部分,还有一个时间戳来帮助表示顺序。

从队列中消费的每个服务至少负责处理一个组,但可以负责多个。服务可以跨多个服务器运行。

系统必须允许可变数量的消费服务,并允许在服务初始化/销毁时自动重新分配 id。

消息必须实时处理,不允许缓冲。消息必须在其 ID 组内按顺序处理。


问题/限制

Rabbit 不允许在获取之前遍历队列,或者从基于模式的单个队列中获取。

消息中的顺序很重要。虽然我们可以简单地获取最重要的消息并在它们与我们的 id 不匹配时拒绝它们,但这会引入一个问题

为了强制执行顺序处理,我们需要将预取计数值设置为 1。然而,这会引入活锁的可能性,其中服务不断地获得队列的头部,但没有服务获得它可以得到的消息过程,或者很少会严重影响性能。

相反,如果我们将预取计数设置得足够高以合理地缓解这种情况,则它允许无序处理。

在任何一种情况下,将预取计数设置为较低的值似乎都会严重影响性能。


可能的解决方案

多个兔子队列

为每个消费者自动生成一个兔子队列并使用主题交换来自动路由消息似乎是一种可能的解决方案。

但是,这会产生一个问题,如果我们需要在处理该服务的队列之前减少使用服务的数量,那么消息将会丢失。如果服务死亡并且无法重新启动替换,也会导致消息丢失。

协调员/工人

我目前的想法是有一个协调服务,它从队列中读取并根据 id 将消息分发给工作人员。

虽然这会引入单点故障,但可以创建多个协调进程,这些进程将通过zookeeper传达哪个工作人员负责给定 id 。

这将需要以下模式之一;

  • 推送:每个协调员都会维护一份所有工作人员的列表,并在他们进来时推送消息。
  • 全局拉取:每个工作人员将轮询所有协调器以获取消息并在本地对它们进行排序和处理,
  • 本地拉取:工作人员将保持与单个协调器的连接,协调器将在它们之间传递消息。

问题

  1. Master/Worker 模型是解决这个问题的可行方案吗?如果是这样;
    • 协调器如何跨服务器与工作人员进行通信?(同时避免如上所述的多个兔子队列问题)
    • 类似地,如果我们使用前面概述的 Local Pull 方法,协调器如何在彼此之间传递消息。
  2. 还有其他我忽略的解决方案吗?

任何帮助深表感谢

4

1 回答 1

2

对于这个问题,这可能不是正确的 Stack Exchange,但我会通过在几件事上纠正你来尝试一下。

为了强制执行顺序处理,我们需要将预取计数值设置为 1。然而,这会引入活锁的可能性,其中服务不断地获得队列的头部,但没有服务获得它可以得到的消息过程,或者很少会严重影响性能。

我不明白这个问题......只有服务可以处理所有消息才能订阅队列。也只绑定队列可以处理的路由键。

在任何一种情况下,将预取计数设置为较低的值似乎都会严重影响性能。

基本上预取计数应该等于工人的数量,否则你得到的好处很少。问题是你不能在不丢失顺序的情况下做两件多件事情(即并行运行的多个工作)。

因此,由于多个并行工作人员而不是预取计数而导致顺序丢失。

如果服务死亡并且无法重新启动替换,也会导致消息丢失。

不,这不应该发生。如果您的服务没有ack消息,则消息不会丢失。只是不要删除队列并使它们持久。但是,如果您动态添加队列和绑定,我认为这是您想说的,那么如果绑定(路由键)没有及时声明,您可能会丢失消息。您可以通过死信交换来处理这个问题

您的一般问题是我认为您希望能够将工作人员添加到队列中并仍然保持秩序。这是一个很难大规模解决的问题。你应该看看 Twitter 是如何做到这一点的。

有几个想法是弄清楚你可以“散列”什么以及你可以在什么上排队。例如,您可以为某个地理区域中的所有用户排队,从而为这些地区的人们保留顺序。这实际上取决于您的业务问题。

于 2013-03-19T12:54:05.710 回答