Skip to content

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

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

简单说:要搬的是「某个队列的消息」,用 Shovel;要建的是「集群之间的长期拓扑」,用 Federation。两者都不要求参与的 Broker 运行相同版本的 RabbitMQ 和 Erlang,这正是它们和集群(cluster)的关键差别;但它们也都不是高可用方案,单个 Broker 内部的数据冗余要靠仲裁队列(quorum queue)。两者提供的都是至少一次语义,消费端的幂等是前提。

一、消息流向的差别 ​

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

1.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 迁出或对接第三方系统时很有用。

1.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 接进监控,链接断开要告警;同时观察上游队列积压。配置了链接也不等于不丢消息:源侧未确认、目标不可用时消息会堆积,需要容量规划。Federation 的单个链接是单向的,双向复制要在两侧各配一个,并避免消息回环。
  • 消息重复:两者都是至少一次语义,下游消费必须幂等。

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


参考资料

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