交换机到交换机绑定
RabbitMQ 2.1.1 版本带来了对交换机之间绑定的支持。这是 AMQP 规范的扩展,使用此功能将(目前)导致您的应用程序只能与 RabbitMQ 配合使用,而无法与市面上其他众多 AMQP 0-9-1 消息中间件兼容。然而,这项扩展极大地提高了路由拓扑的表达能力和灵活性,并同时解决了一些可伸缩性问题。
常规绑定允许交换机绑定到队列:发布到交换机的消息,只要满足交换机及其绑定的各种条件,就会通过各种绑定,并最终附加到每个绑定末尾的队列中。这对于许多用例来说已经足够了,但灵活性非常有限:它总是只有一步——消息被发布到一个交换机,具有一套绑定,因此只有一套可能的目的地。如果您需要更灵活的方式,则不得不多次发布同一条消息。通过交换机到交换机绑定,一条消息可以经过任意数量的不同类型的交换机,实现比以往任何时候都更复杂的路由拓扑。
示例:日志记录
设想一个通用的日志记录场景:您想“窃听”RabbitMQ 中消息流的各个部分,以检查特定交换机上传输的消息流。您无法直接对队列进行此操作,因此最显而易见的解决方案是添加一个新队列作为您的日志队列,并将其绑定到您感兴趣的交换机。现在,根据交换机的类型和您的绑定键,您可能会收到该交换机上传输的零条、部分或全部消息。这可以用以下图表表示
但是,如果您有多个日志队列该怎么办?您可能有一个用于 syslog,一个用于控制台,一个用于第三方管理软件。将所有这些视为一个单一实体会更简单,因此只需要像上面那样添加一个绑定,将所有这些连接到同一个源交换机。通过交换机到交换机绑定,您现在可以做到这一点
现在,我们有了现有的日志交换机,以及几个从它接收所有消息的队列,我们只需要添加一个新绑定(在RabbitMQ-orange中)连接到您感兴趣的交换机和我们的日志交换机。虽然这里的两个交换机都是 fanout 类型,但不必如此:我们可能需要不同的日志队列,它们只对流经日志交换机的消息子集感兴趣。因此,该交换机可以是一个 topic 交换机
所以现在,syslog 只会收到错误(即路由键以 error. 开头的消息),而 console 会收到所有消息。但在两种情况下,无论消息来源如何,这种行为都适用:日志交换机都可以根据需要绑定到零个、一个或多个交换机
用法
现有的 queue.bind AMQP 方法,从其命名来看,表明您执行的操作是“将队列绑定到交换机”。这有点令人困惑,因为消息实际上是从交换机流经绑定,然后到达队列。但是,简单之处在于该方法包含一个用于 queue 名称、exchange 名称和绑定键的字段。
我们引入了 exchange.bind 和 exchange.unbind AMQP 方法。遗憾的是,由于此类绑定的两个端点都是交换机,并且我们无法同时使用两个名为 exchange 的字段,因此我们不得不采用不同的命名方案。我们在这里选择反映消息流。因此,source 字段表示消息进入绑定的交换机的名称,而 destination 字段表示消息传递到的交换机的名称。
我们在 Java、.Net 和 Erlang 客户端中增加了对交换机到交换机绑定的支持。我们希望其他社区贡献的客户端也能尽快添加支持。
由 exchange.bind 创建的绑定在语义上与 queue.bind 绑定相同:单向,绑定键和交换机类型按正常工作,但绑定的两个端点(源和目标)都是交换机。
就像 queue.bind 一样,可以在相同的绑定端点之间创建多个独立的绑定。我们在消息传递过程中检测并消除循环,并确保在任何路由拓扑中,对于给定消息路由到的每个队列,每个队列将接收到该消息的确切一份副本。声明为 auto-delete 的交换机将在与其作为源的所有绑定被移除后仍会被移除,无论这些绑定的目标是队列还是交换机。请注意,当作为源的交换机的绑定全部移除后,该 auto-delete 交换机才会被删除:如果您添加的交换机到交换机绑定中该交换机是目标,那么在移除这些绑定时该交换机不会被 auto-delete。这与 auto-delete 队列在与其绑定的移除时不会被删除的事实相呼应。
示例 2:在线状态
设想一个聊天系统。每个用户都有一个队列,其中包含发送给该用户的所有消息。该队列还应接收在线状态通知:表明某人上线或离线的事件。
我们假设的这个人叫 John。当 John 上线时,他将向 presence 交换机发布一条消息,表明他在线且可供聊天。presence 交换机将是一个 direct 交换机,John 将他的在线状态发布到该交换机,路由键为“John”。因此,John 的所有朋友都需要订阅 presence 交换机(即,他们需要将自己的队列绑定到该交换机),绑定键为“John”。登录时,John 本人需要将他的队列绑定到 presence 交换机,每个朋友绑定一次:每个绑定携带不同的 binding key(例如,绑定键为 Alice,Bill 等)。整个系统(仅就在线状态而言)可能看起来像这样
这里我们看到 John 是 Alice 和 Bill 的朋友(因此他从 presence 交换机到他自己的队列绑定,路由键为 Alice 和 Bill)。Alice 和 Bill 之间不是朋友,但他们各自都有几个朋友,其中包括 John。
因此,当每个人上线时,他们都必须创建自己的队列,并为每个朋友创建到该队列的绑定。在一个大型聊天系统中,平均朋友数量约为 20 人,并且每分钟可能有数百甚至数千人上线或下线。此时,绑定中的流失率可能成为严重的性能瓶颈。通过交换机到交换机绑定,这个问题可以得到解决。诀窍在于允许友谊关系仅通过交换机到交换机绑定来表达,这些绑定即使在用户离线时也可以保留。当用户上线时,他们只需要创建自己的队列和一个绑定
一如既往,路由到没有绑定的交换机的消息就会消失,因此如果 John 离线,就没有缓冲:John_queue 不存在:在这种情况下,John 交换机丢弃发送给它的所有消息。因此,结果是交换机到交换机绑定网格只需要在人们添加或删除朋友时进行修改,并且用户上线或下线引起的负载大大减少。
这仅仅是开始:通过交换机到交换机绑定,现在可以实现更复杂的路由拓扑了……