RabbitMQ 跨集群:Shovel 与 Federation 怎么选
两个插件都能把消息从一个 Broker 送到另一个,区别在于视角:Shovel 是「我要把这个队列的消息搬到那边去」,Federation 是「让那边的消息流在我这里也有一份」。选错了会在迁移或容灾时发现配置方式完全不对。
简单说:要搬的是「某个队列的消息」,用 Shovel;要建的是「集群之间的长期拓扑」,用 Federation。两者都不要求参与的 Broker 运行相同版本的 RabbitMQ 和 Erlang,这正是它们和集群(cluster)的关键差别;但它们也都不是高可用方案,单个 Broker 内部的数据冗余要靠仲裁队列(quorum queue)。两者提供的都是至少一次语义,消费端的幂等是前提。
一、消息流向的差别
1.1 Shovel
Shovel 本质上是 Broker 内部运行的一个 AMQP 客户端:
- 连接到源(通常是本地)和目标(通常是远程)Broker;
- 从源队列消费消息;
- 发布到目标的交换机或队列;
- 目标确认之后,再向源队列发送 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 的设计目标是在不可靠的广域网上工作:链接断开后会自动重连,消息在上游侧缓冲。
二、对比
| 维度 | Shovel | Federation |
|---|---|---|
| 视角 | 明确的源与目的地 | 上游与下游的拓扑关系 |
| 配置位置 | 运行 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。
参考资料