Skip to content

RabbitMQ 跨集群:Shovel 与 Federation 怎么选 ​

两个插件都能把消息从一个 Broker 送到另一个,区别在于视角:Shovel 是「我要把这个队列的消息搬到那边去」,Federation 是「让那边的消息流在我这里也有一份」。选错了会在迁移或容灾时发现配置方式完全不对。

一、先说结论 ​

  • Shovel 是点对点搬运:从指定的源队列消费,重新发布到指定的目标交换机或队列,方向单一、配置明确。
  • Federation 是链路复制:联邦交换机会把上游交换机收到的消息在下游「重放」一份;联邦队列则在本地没有消费者可用时,从上游队列拉取消息。
  • 两者都不要求集群同版本:官方文档明确说明,参与的 Broker 可以运行不同版本的 RabbitMQ 和 Erlang,这正是它们与集群(cluster)的关键差别——集群要求版本一致且网络可靠。
  • 一次性迁移、定向复制用 Shovel;长期的跨机房拓扑、多活消费用 Federation。
  • 两者都不是高可用方案:它们跨的是 Broker,不负责单个 Broker 内部的数据冗余,后者靠仲裁队列(quorum queue)。

二、消息流向的差别 ​

Shovel:点对点搬运源 Broker队列Shovel消费 + 重新发布目标 Broker交换机 / 队列Federation:上游到下游的复制上游 Broker交换机 / 队列Federation 链接按策略建立下游 Broker本地副本
图 1 · Shovel 是一个内置的客户端,把源队列的消息搬到目标交换机;Federation 让上游交换机的消息流被下游「重放」一份

2.1 Shovel ​

Shovel 本质上是 Broker 内部运行的一个 AMQP 客户端:

  1. 连接到源(通常是本地)和目标(通常是远程)Broker;
  2. 从源队列消费消息;
  3. 发布到目标的交换机或队列;
  4. 目标确认之后,再向源队列发送 ack。

因为有确认机制,默认提供至少一次投递语义:网络中断时消息不会丢,但可能重复,下游要幂等。

配置方式(动态 Shovel,通过管理插件或 HTTP API 下发):

bash
rabbitmqctl set_parameter shovel migrate-orders '{
  "src-protocol": "amqp091",
  "src-uri": "amqp://user:***@source-host",
  "src-queue": "orders",
  "dest-protocol": "amqp091",
  "dest-uri": "amqp://user:***@target-host",
  "dest-exchange": "orders-ex"
}'

Shovel 还可以把消息送到其他兼容 AMQP 的 Broker,这在从 RabbitMQ 迁出或对接第三方系统时很有用。

2.2 Federation ​

Federation 通过策略(policy)建立上下游链接,有两种形态:

  • 联邦交换机(federated exchange):下游交换机会收到上游交换机收到的消息副本。适合「一份消息,多个机房都要消费」的广播型场景。
  • 联邦队列(federated queue):下游队列在本地消费者空闲时,从上游队列拉取消息。适合把消费能力分散到多个机房,同一条消息只被一个消费者处理。
bash
# 定义上游
rabbitmqctl set_parameter federation-upstream bj-dc '{"uri":"amqp://user:***@bj-host","expires":3600000}'
# 用策略把匹配的交换机联邦起来
rabbitmqctl set_policy --apply-to exchanges federate-orders "^orders\." '{"federation-upstream":"bj-dc"}'

Federation 的设计目标是在不可靠的广域网上工作:链接断开后会自动重连,消息在上游侧缓冲。

三、对比 ​

维度ShovelFederation
视角明确的源与目的地上游与下游的拓扑关系
配置位置运行 Shovel 的那个 Broker下游 Broker(通过 policy 匹配)
粒度单个队列 / 交换机按策略匹配一批交换机或队列
方向单向单向,可以配置成多个上游形成网状
目标类型RabbitMQ 或其他 AMQP Broker只能是 RabbitMQ
典型用途迁移、定向复制、对接异构系统跨机房拓扑、多活消费、广域分发
版本要求不要求一致不要求一致

四、怎么选 ​

用 Shovel 的场景:

  • 集群迁移:老集群的消息搬到新集群,迁移完成后删掉 Shovel。
  • 定向复制:把生产环境某个队列的消息复制一份到分析或测试环境。
  • 对接非 RabbitMQ:目标是其他 AMQP Broker。
  • 灾备:把关键队列的消息持续送到备用站点。

用 Federation 的场景:

  • 跨机房的长期拓扑:多个机房各有一套 RabbitMQ,消息需要互通。
  • 广播型分发:一份消息要在多个区域被各自消费(联邦交换机)。
  • 消费能力分散:一个队列的消息由多个机房的消费者分担(联邦队列)。
  • 管理域分离:两个集群由不同团队维护、用户和权限各自独立。

五、部署与排查 ​

bash
# 启用插件(集群中的每个节点都要启用)
rabbitmq-plugins enable rabbitmq_shovel rabbitmq_shovel_management
rabbitmq-plugins enable rabbitmq_federation rabbitmq_federation_management

# 查看状态
rabbitmqctl shovel_status
rabbitmqctl federation_status

几个容易踩的点:

  • 集群里每个节点都要启用插件,否则链接会在部分节点上不可用。
  • TLS 证书校验:Erlang 26 起默认开启客户端对端证书校验,升级后原本能连上的 TLS 链接可能突然失败,需要正确配置 CA 与证书。
  • 凭据管理:URI 里包含用户名密码,要用配置中心或密钥管理,不要写进代码仓库。
  • 监控链接状态:把 shovel_status / federation_status 接进监控,链接断开要告警;同时观察上游队列积压。
  • 消息重复:两者都是至少一次语义,下游消费必须幂等。

六、常见误区 ​

  • 「Shovel 和 Federation 能替代集群」:它们在独立 Broker 之间搬运消息,不提供单个 Broker 的数据冗余与高可用。
  • 「配置了就一定不丢消息」:源侧未确认、目标不可用时消息会堆积,需要监控和容量规划。
  • 「Federation 是双向同步」:单个链接是单向的,双向需要在两侧各配一个,并注意避免消息回环。
  • 「跨集群要求版本一致」:官方明确支持不同版本的 RabbitMQ 与 Erlang。

小结 ​

选择很简单:要搬的是「某个队列的消息」,用 Shovel;要建的是「集群之间的长期拓扑」,用 Federation。 前者配置直接、适合一次性任务,后者用策略批量管理、适合常态化的跨机房结构。两者都提供至少一次语义,所以消费端的幂等是前提,而单个集群的高可用仍然要靠仲裁队列来解决。

消息重复与幂等消费的通用做法,见 Kafka 不丢、不重与 Exactly Once。


参考资料

文章以 CC BY-NC-SA 4.0 授权 · 代码片段以 MIT 授权