我正在使用RabbitMQ的循环功能在多个消费者之间发送消息,但其中只有一个消费者一次收到实际消息。
我的问题是我的消息代表任务,我希望在我的消费者身上有本地会话(状态)。我事先知道哪些消息属于哪个会话,但我不知道使用我指定的算法将RabbitMQ调度给消费者的最佳方式是什么(或者有办法吗?)。
我不想编写自己的业务流程服务,因为它会成为瓶颈,我不希望我的生产者知道哪些消费者会接收他们的消息,因为我将失去使用Rabbit的解耦。
有没有办法让RabbitMQ根据预先定义的算法/规则而不是循环法向消费者发送消息?
澄清:我使用了几种用不同语言编写的微服务,每项服务都有自己的工作。我使用protobuf消息在他们之间进行通信。我给每封新邮件UUID
。如果消费者收到消息,它可以从创建响应消息(这可能不是正确的术语,因为生产者和消费者是分离的,他们彼此不了解)和这个{{ 1}}被复制到新消息。这形成了一个数据转换管道,这个“process”由UUID
( processId )标识。我的问题是,我可能有多个工作者消费者,如果之前已经看过,我需要一个工人坚持到UUID
。我有这个需要,因为
由于RabbitMQ使用循环法在工作人员之间分配任务,因此无法强制我的进程粘在工作者身上。我有几点需要注意:
如果有一个解决方法不涉及更改循环算法并且不会破坏我的约束,那也没关系!
答案 0 :(得分:6)
如果您不想使用业务流程服务,可以尝试这样的拓扑:
为简单起见,我假设您的processId
被用作路由键(在现实世界中,您可能希望将其存储在标题中并使用header
交换)。
Incoming Exchange (类型:直接)接受传入消息,其alternative-exchange
属性设置为指向No Session Exchange
(扇出)。
以下是RabbitMQ文档在“替代交换”中所说的内容:
有时候希望让客户端处理交换无法路由的消息(即,因为没有绑定队列我们没有匹配的绑定)。
典型的例子是
- 检测客户端何时意外或恶意发布无法路由的邮件
- "或者"路由语义,其中一些消息是专门处理的,其余的是通用处理程序
RabbitMQ的备用交换(" AE")功能解决了这些用例。
(我们对这里的or else
用例特别感兴趣)
每个消费者都会创建自己的队列并将其绑定到 Incoming Exchange ,使用processId(s)
进行目前已知的会话,如绑定路由密钥。
这样它只会获得它感兴趣的会话的消息。
此外,所有消费者都将绑定到共享的 No Session Queue 。
如果包含以前未知processId
的邮件,则 Incoming Exchange 中没有特定的绑定,因此会重新路由到无会话交换 => 无会话队列并以通常(循环)方式分派给其中一个消费者。
然后,消费者将使用 Incoming Exchange (即启动新的"会话")为其注册新的绑定,以便随后获取所有后续消息使用此processId
。
一次"会话"结束它将必须删除相应的绑定(即关闭"会话")。