我可以使用RabbitMQ使用自定义算法而不是循环法调度消息吗?

时间:2017-03-24 14:10:35

标签: java algorithm rabbitmq

我正在使用RabbitMQ的循环功能在多个消费者之间发送消息,但其中只有一个消费者一次收到实际消息。

我的问题是我的消息代表任务,我希望在我的消费者身上有本地会话(状态)。我事先知道哪些消息属于哪个会话,但我不知道使用我指定的算法将RabbitMQ调度给消费者的最佳方式是什么(或者有办法吗?)。

我不想编写自己的业务流程服务,因为它会成为瓶颈,我不希望我的生产者知道哪些消费者会接收他们的消息,因为我将失去使用Rabbit的解耦。

有没有办法让RabbitMQ根据预先定义的算法/规则而不是循环法向消费者发送消息?

澄清:我使用了几种用不同语言编写的微服务,每项服务都有自己的工作。我使用protobuf消息在他们之间进行通信。我给每封新邮件UUID。如果消费者收到消息,它可以从创建响应消息(这可能不是正确的术语,因为生产者和消费者是分离的,他们彼此不了解)和这个{{ 1}}被复制到新消息。这形成了一个数据转换管道,这个“process”UUID processId )标识。我的问题是,我可能有多个工作者消费者,如果之前已经看过,我需要一个工人坚持UUID。我有这个需要,因为

  1. 每个进程可能都有本地状态
  2. 进程完成后,我想清理本地状态
  3. 微服务可能会收到同一进程的多条消息,我需要区分哪个消息属于哪个进程
  4. 由于RabbitMQ使用循环法在工作人员之间分配任务,因此无法强制我的进程粘在工作者身上。我有几点需要注意:

    • 生产者与消费者脱钩,因此直接消息传递不是一种选择
    • 工作人员数量不是恒定的(有一个可能启动工人新实例的负载均衡器)

    如果有一个解决方法不涉及更改循环算法并且不会破坏我的约束,那也没关系!

1 个答案:

答案 0 :(得分:6)

如果您不想使用业务流程服务,可以尝试这样的拓扑:

enter image description here

为简单起见,我假设您的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

一次"会话"结束它将必须删除相应的绑定(即关闭"会话")。