我目前正在重新设计一个系统并且遇到了一些麻烦。
要求
我有一个消息队列(一个RabbitMQ队列)和一些从该队列消耗的服务。每条消息都有一个 id 表示它是一个组的一部分,还有一个时间戳来帮助表示顺序。
从队列中消费的每个服务至少负责处理一个组,但可以负责多个。服务可以跨多个服务器运行。
系统必须允许可变数量的消费服务,并允许在服务初始化/销毁时自动重新分配 id。
消息必须实时处理,不允许缓冲。消息必须在其 ID 组内按顺序处理。
问题/限制
Rabbit 不允许在获取之前遍历队列,或者从基于模式的单个队列中获取。
消息中的顺序很重要。虽然我们可以简单地获取最重要的消息并在它们与我们的 id 不匹配时拒绝它们,但这会引入一个问题
为了强制执行顺序处理,我们需要将预取计数值设置为 1。然而,这会引入活锁的可能性,其中服务不断地获得队列的头部,但没有服务获得它可以得到的消息过程,或者很少会严重影响性能。
相反,如果我们将预取计数设置得足够高以合理地缓解这种情况,则它允许无序处理。
在任何一种情况下,将预取计数设置为较低的值似乎都会严重影响性能。
可能的解决方案
多个兔子队列
为每个消费者自动生成一个兔子队列并使用主题交换来自动路由消息似乎是一种可能的解决方案。
但是,这会产生一个问题,如果我们需要在处理该服务的队列之前减少使用服务的数量,那么消息将会丢失。如果服务死亡并且无法重新启动替换,也会导致消息丢失。
协调员/工人
我目前的想法是有一个协调服务,它从队列中读取并根据 id 将消息分发给工作人员。
虽然这会引入单点故障,但可以创建多个协调进程,这些进程将通过zookeeper传达哪个工作人员负责给定 id 。
这将需要以下模式之一;
- 推送:每个协调员都会维护一份所有工作人员的列表,并在他们进来时推送消息。
- 全局拉取:每个工作人员将轮询所有协调器以获取消息并在本地对它们进行排序和处理,
- 本地拉取:工作人员将保持与单个协调器的连接,协调器将在它们之间传递消息。
问题
- Master/Worker 模型是解决这个问题的可行方案吗?如果是这样;
- 协调器如何跨服务器与工作人员进行通信?(同时避免如上所述的多个兔子队列问题)
- 类似地,如果我们使用前面概述的 Local Pull 方法,协调器如何在彼此之间传递消息。
- 还有其他我忽略的解决方案吗?
任何帮助深表感谢