RabbitMQ:如何组合任务队列和 fanout/routing/topic 模型?

RabbitMQ: How to combine a task queue and a fanout/routing/topic models?

我有一个包含一个生产者和多个消费者的环境。
生产者创建 2 种类型的消息:

  1. 只需要一个消费者处理的消息(任何消费者都可以)。
  2. 需要所有消费者处理的消息。

如何实施?
对于消息类型 1,工作队列是合适的模型。
对于消息类型 2,fanout/direct/routing/topic 是合适的。
但是我该如何组合它们呢?

直接与扇出路由是 RabbitMQ 交换的属性。所有 RabbitMQ 消息都发布到交换器,而不是直接发布到队列——当您创建和使用队列而不显式创建交换器时,您实际上是在使用预先声明的默认交换器。

您可以在一个 RabbitMQ 代理上创建多个交换器,并且可以将一个队列绑定到多个交换器。如果您希望工作人员对两种消息类型使用相同的队列,您可以创建一个直接交换(对于消息类型 1)和一个扇出交换(对于消息类型 2)并将每个队列绑定到这两个交换。否则,您可以为每种交换类型创建单独的队列。

RabbitMQ 的 AMQP concept guide has a good explanation of exchanges and queues, and Tutorial 3 on the RabbitMQ Getting Started 页面向您展示了如何创建和绑定交换。

RabbitMQ 非常灵活,您可以有许多不同的交换和队列设计解决方案来满足您的要求。

但是,首先,我们需要了解队列和消费者之间的关系和基本规则:

  • 如果你想让一个消息类型只被所有消费者中的一个消费,就像你说的,你需要一个工作队列,所有的消费者都应该订阅它。
  • 如果你想让一个消息类型被每个消费者消费,你需要为每个消费者都有队列,并且每个消费者只订阅自己的队列。

当队列数根据上面的理解清楚了。剩下的就是如何将您的消息路由到这些队列。会有很多解决方案。以下只是一些示例。

一个可行的解决方案是创建两个交换器,一个用于每种消息类型。

| message type | exchange name | exchange type | bound queues      |
|------------------------------------------------------------------|
| type_1       | exchange1     | fanout        | shared_queue      |
| type_2       | exchange2     | fanout        | queue1,queue2,... |

另一种可行的解决方案是,如果您希望只有一个交换来发布两种消息类型,请使用 'direct' 交换类型:

| routing_key | binding_key | bound queues      |
|-----------------------------------------------|
| type_1      | type_1      | shared_queue      |
| type_2      | type_2      | queue1,queue2,... |

一个交换器可以使用相同的绑定键绑定多个队列。因此,当使用发布路由键 "type_1" 发布消息类型 1 时,只有 shared_queue 会收到消息;使用发布路由键发布消息类型 2 时 - "type_2",所有队列 1、队列 2... 都将收到消息。

如果您有更多消息类型并且不想使用相同的路由密钥,则对每条消息使用不同的绑定密钥可能不适合实际情况。如果是这样,您可能想改用 "topic" 交换类型:

| routing_key | binding_key | bound queues      |
|-----------------------------------------------|
| type_1.1    | type_1.*    | shared_queue      |
| type_2.2    | type_2.*    | queue1,queue2,... |