交换机到交换机的绑定
RabbitMQ 2.1.1 引入了对交换机之间绑定的支持。这是 AMQP 规范的扩展,使用此功能将(目前)导致您的应用程序只能与 RabbitMQ 兼容,而不能与其他众多的 AMQP 0-9-1 代理实现兼容。但是,此扩展极大地提高了路由拓扑的表达力和灵活性,同时解决了某些可扩展性问题。
普通绑定允许交换机绑定到队列:发布到交换机的消息,只要满足交换机及其绑定的各种条件,就会通过各种绑定并追加到每个绑定末尾的队列中。这对许多用例来说已经足够了,但灵活性很差:它始终只有一跳——消息发布到一个交换机,并具有一组绑定,因此只有一组可能的目的地。如果您需要更灵活的功能,则必须诉诸多次发布相同的消息。使用交换机到交换机的绑定,只需发布一次消息,即可流经任意数量的交换机,并具有不同类型和比以前更复杂的路由拓扑。
示例:日志记录
想象一个通用的日志记录场景:您希望“截取”RabbitMQ 中消息流的各个部分,以检查流经该特定交换机的消息流。您无法对队列执行此操作,因此最明显的解决方案是添加一个新的队列作为您的日志记录队列,并将其绑定到您感兴趣的交换机。现在,根据交换机类型和绑定键,您可能会收到部分或全部通过该交换机传递的消息。这可以用下图表示
但是,如果您有多个日志记录队列会怎样——您可能有一个用于 syslog,一个用于控制台,一个用于某些第三方管理软件。将所有这些都视为单个实体会简单得多:因此需要添加一个绑定,如上所示,将所有这些绑定到相同的源交换机。使用交换机到交换机的绑定,您现在可以做到这一点
现在,我们现有的日志记录交换机有几个队列接收来自它的所有消息,我们只需要添加一个新的绑定(在 RabbitMQ-orange 中)在我们感兴趣的交换机和我们的日志记录交换机之间。虽然这两个交换机都是扇出型,但没有必要这样做:我们可能会有不同的日志记录队列,它们只对流经日志记录交换机的一部分消息感兴趣。因此,该交换机很可能是主题交换机
因此,现在我们知道 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
队列不会被删除的事实。
示例 2:状态
想象一个聊天系统。每个用户都将拥有一个队列,其中包含发送给该用户的所有消息。该队列还应发送状态通知:指示用户朋友是否上线或下线的事件。
我们假想的人叫 John。当 John 上线时,他将向交换机 presence
发布一条消息,说明他已上线并可以聊天。因此,presence
交换机将是一个 direct
交换机,John 将使用 routing key
“John” 将其状态发布到该交换机。因此,John 的所有朋友都需要订阅 presence
交换机(即,他们需要从该交换机到其自身队列的绑定),并使用绑定键“John”。登录时,John 本身需要将其队列绑定到 presence
交换机,每个朋友一个绑定:每个绑定都带有不同的 binding key
(例如,绑定键为 Alice
、Bill
等)。整个系统(仅限于状态)可能如下所示
在这里,我们看到 John 与 Alice 和 Bill 是朋友(因此他使用路由键 Alice
和 Bill
将其队列绑定到 presence 交换机)。Alice 和 Bill 不是朋友,但他们每个人都有其他几个朋友,每个朋友都包括 John。
因此,当每个人上线时,他们必须创建其队列,并且必须为其每个朋友创建到该队列的绑定。在一个大型聊天系统中,平均朋友数量可能约为 20,并且可能每分钟有数百甚至数千人上线或下线。此时,绑定的更新率可能会成为严重的性能瓶颈。使用交换机到交换机的绑定,可以解决此问题。诀窍是允许仅通过交换机到交换机的绑定来表达朋友关系,即使用户下线也可以保留这些绑定。当用户上线时,他们只需要创建其队列和一个绑定
像往常一样,路由到没有绑定的交换机的消息只是消失,因此如果 John 离线,则不会进行缓冲,因此 John_queue
不存在:在这种情况下,交换机 John
将丢弃发送到它的所有消息。因此,结果是,仅当人们添加朋友或删除朋友时,交换机到交换机的绑定网格才需要修改,并且朋友上线或下线导致的负载大大减少。
这仅仅是一个开始:使用交换机到交换机的绑定,现在可以实现更复杂的路由拓扑……