插件URL地址:https://www.rabbitmq.com/federation.html
Federation 插件的设计目标是使 RabbitMQ 在没有搭建集群的情况下也能在 Broker 节点之间进行消息传递,该功能在很多场景下都非常有用。
Federation 插件可以让多个交换器或者多个队列进行 Federation。一个 Federation 交换器(Federation Exchange)或者一个 Federation 队列(Federation Queue)接收上游的消息,这里的上游是指位于其他 Broker 上的交换器或者队列。Federation 交换器能够将原本发送给上游交换器的消息路由到本地的某个队列中;Federation 队列则允许一个本地消费者接收到来自上游队列的消息。
Federation 插件能够在不同管理域中的 Broker 或者 RabbitMQ 集群之间传递消息。这些 Broker 可能设置了不同的用户和 vhost ,也可能运行在不同版本的 RabbitMQ 和 Erlang 之上。
Federation 插件基于 AMQP 0-9-1 协议在不同的 Broker 之间进行通信,并设计成能够容忍网络连接不稳定的情况。
Broker 节点中可以同时存在 Federation 交换器(或队列)或者本地交换器(或队列),只需要对特定的交换器(或队列)创建 Federation 连接。
Federation 不需要在 Broker 节点之间创建 O(N2) 个连接(尽管这是最简单的使用方式),这也就意味着 Federation 在使用时更容易扩展。
假设我们应用在北京机房部署 breaker1,在成都机房部署 breaker2。如下图:
上图中,北京有一个“客户端B”需要向成都机房 breaker2 发送一条消息。由于 breaker1 和 breaker2 位于两个区域,存在较大的网络延迟,尤其是在开启了 publisher confirm 机制或者事务机制的情况下,“客户端B”会等待很长的延迟时间来接收成都机房 broker2 的确认信息,进而必然造成这条发送消息的线程的性能下降,甚至造成一定程度上的阻塞。
那么要怎么优化“客户端B”发送消息呢?将“客户端B”调用成都机房的业务部署到北京机房中可以解决这个问题,如果“客户端B”调用了其他节点的其他服务,那么又会引发新的时延问题,总不见得将所有业务全部部署在一个机房,那么容灾又何以实现?
使用 Federation 插件就可以很好地解决这个问题,如下图:
上图中,在成都机房的 broker2 中为交换器 exchangeB 与北京机房的 broker1 之间建立一条单向的 Federation 连接。此时 Federation 插件会在北京机房的 broker1 上会建立一个同名的交换器 exchangeB,同时建立一个内部交换器,并通过路由键将exchangeB 交换器和内部交换器进行绑定。与此同时,Federation 插件还会在北京机房的 brokerl 上自动建立一个本地队列并与前面的内部交换器进行绑定。
Federation 插件会在北京机房的 broker1 中本地队列与成都机房的 broker2 中的交换器 exchangeB 之间建立一条 AMQP 连接来实时地消费北京机房 broker1 中本地队列中的数据。
Federation 插件不仅便利于消息生产方,同样也便利于消息消费方。
注意:
Federation 交换器可以成为另一个交换器的上游交换器
一个交换器可以是 Federation 交换器的同时也是上游交换器,如:A和B两个交换器相互建立 Federation 连接。
对于默认的交换器(每个虚拟机 vhost 下都会默认创建一个名为 “” 的交换器)和内部交换器而言,不能对其使用 Federation 功能。
除了 Federation 交换器,RabbitMQ 还支持 Federation 队列。Federation 队列可以在多个 Broker 节点(或者集群〉之间为单个队列提供均衡负载的功能。一个 Federation 队列可以连接一个或者多个上游队列(Upstream Queue),并从这些上游队列中获取消息以满足本地消费者消费消息的需求。如下图:
上图中,队列A 和 队列B 原本在成都机房 broker2 中,由于某种需求将其配置为 Federation 队列并将北京机房的 brokerl 作为 上游 broker。Federation 插件会在北京机房的 broker1 上创建同名的队列A和队列B,与成都机房的 broker2 中的队列A和队列B分别建立两条单向独立的 Federation 连接。
此时,当有消费者A连接到成都机房的 broker2,并通过 Basic.Consume 消费队列A和队列B中的消息时。有如下情况:
(1)如果 broker2 中,队列A或队列B中有很多消息堆积,那么消费者A直接消费这些消息。此时成都机房的 broker2 中的队列A和队列B并不会从北京机房 brokerl 中的队列A和队列B拉取消息。
(2)如果 broker2 中,队列A或队列B中没有消息堆积或者消息被消费完了,那么它会通过 Federation 连接从北京机房 broker1 中的队列A和队列B中拉取消息(如果有消息),然后存储到本地,之后再被消费者A进行消费。
消费者既可以消费 broker2 中的队列,又可以消费 brokerl 中的队列,Federation 的这种分布式队列的部署可以提升单个队列的容量。如果在 brokerl 一端部署的消费者来不及消费队列中的消息,那么 broker2 端部署的消费者可以为其分担消费,也可以达到某种意义上的负载均衡。
注意:
(1)一条消息可以在 Federation 队列间转发无限次。例如:消费者A从“broker1.队列A”中消费消息,消费者B从“broker2.队列A”中消费消息。如果此时“broker1.队列A”中消息堆积太多,而“broker2.队列A”没有消息,则会将消息从“broker1.队列A”转移到“broker2.队列A”,有消费者B消费,分担消费压力。由于某些原因,“broker1.队列A”中消息快速被消费完成,而“broker2.队列A”中还有堆积消息没有消费,则再次会将消息从“broker2.队列A”中自动转移一部分到“broker1.队列A”,分摊消费者B的压力。
(2)Federation 队列不具备传递性。例如:有队列A、队列B、队列C三个队列,队列A和队列B建立 Federation 连接,队列B和队列C建立 Federation 连接。队列B如果有消费者,没有消息时可以从队列A拉取消息消费。队列C如果有消费者,没有消息时可以从队列B拉取消息消费。遗憾的是,队列C并不能从队列A拉取消息,即使队列C存在消费者且没有消息,也不会从队列A拉取消息。