bigywater.tech
RabbitMQ · 30

Shovel 与 Federation

跨数据中心、跨集群搬消息有两个官方工具:Shovel 和 Federation。它们各是什么、怎么配、目的端挂了会怎样、消息是被复制还是被搬走?这篇起了两个独立的 broker,把两者各跑一遍。

22106 条/秒
on-confirm 的 shovel 在本机上搬 20000 条消息的速度
0.4 s
目的端 B 重新可用后,积压的 500 条消息被搬完所需的时间
5 / 6
交换机联邦只复制了下游绑定 orders.# 感兴趣的 5 条,没有复制 other.x

Shovel

实测 · 本机执行输出
  $ rabbitmqctl set_parameter shovel my-shovel '{"src-queue":"src","dest-queue":"dst","ack-mode":"on-confirm",…}'
  shovel_status: [{'name': 'my-shovel', 'type': 'dynamic', 'state': 'running', 'destination_protocol': 'amqp091', 'source_protocol': 'amqp091'}]
  A.src 里剩 0 条,B.dst 里有 1000 条

一个 shovel 就是“在源端当消费者、在目的端当发布者”的进程,用 rabbitmqctl set_parameter shovel 动态定义。ack-mode 决定何时确认源消息:on-confirm 最安全,no-ack 最快但可能丢。

ack-mode

实测 · 本机执行输出
  on-confirm     905 ms     22106 条/秒
  on-publish     974 ms     20533 条/秒
  no-ack         874 ms     22870 条/秒

on-confirm(目的端确认后才确认源)、on-publish(发布后就确认)、no-ack(源端自动确认)三种吞吐几乎一样,约 2 万条/秒,差别在噪声内;越保守越不会丢。

目的端故障

实测 · 本机执行输出
  B 宕机期间 shovel_status: [('my-shovel', 'terminated')];A.src 里积压 500 条
  B 重新启动并可用之后 0.4 s,B.dst 里有 500 条,A.src 里剩 0 条

目的端宕机时 shovel 终止,源队列保留消息;目的端回来后 shovel 重连、继续搬,按 reconnect-delay 重试。

交换机联邦

实测 · 本机执行输出
  $ rabbitmqctl set_parameter federation-upstream up-b '{"uri":"amqp://…B"}'
  $ rabbitmqctl set_policy fed-x "^fx$" '{"federation-upstream-set":"all"}' --apply-to exchanges
  B 上发布 5 条 orders.new + 1 条 other.x;A.fq_local(绑定 orders.#)里有 5 条
  联邦链路状态(eval rabbit_federation_status:status()): [[{exchange,<<"fx">>},   {upstream_exchange,<<"fx">>},   {type,exchange},   {vhost,<<"/">>},   {upstream,<<"up-b">>},   {id,<<"c988aec5">>},   {status,running},   {local_connection,<<"<q30a@localhost.1791861923.3125.0>">>},   {uri,<<"amqp://127.0.0.1:9508">>},

下游的联邦交换机按自己的绑定,向上游交换机拉取匹配的消息(复制),不匹配的不传。用 federation-upstream 参数 + policy 配置。

队列联邦

实测 · 本机执行输出
  建好联邦链路、A 上还没有消费者:A.fqq 0 条,B.fqq 100 条(消息都还在上游)
  A 上开一个消费者后,0.0 s 收到 100 条;B.fqq 里剩 0 条(消息是被"搬"过去的,不是复制)

联邦队列只在下游有消费者时才从上游拉消息,是搬运不是复制;没有消费者时消息留在上游。

分步演示

Shovel 与 Federation
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / RabbitMQ 4.3.6 / Erlang/OTP 28.5 / pika 1.4.4(Homebrew 与临时虚拟环境);所有节点都是本机自己起的 RabbitMQ 进程(127.0.0.1,端口 9500 以上,每个实验独立的数据目录与节点名,不连任何外部服务);命令输出来自真实的 rabbitmqctl 与管理 API,发布与消费用 pika 的真实连接;计时用 time.perf_counter,数字每次运行会有小幅抖动。两个独立节点 A、B(各自数据目录、端口),A 启用 rabbitmq_shovel 与 rabbitmq_federation,B 启用 rabbitmq_federation;吞吐的计时包含创建 shovel 到 B 上收齐;“消息被搬走”由 rabbitmqctl list_queues 的条数佐证
    • 没有验证:AMQP 1.0 shovel;跨广域网的延迟与带宽影响;联邦的 max-hops、expires、message-ttl 等参数;循环联邦(双向)的防环;联邦下游宕机后的行为;shovel 的批量(prefetch-count)调优;大量联邦队列的内存
    京ICP备2026067502号-1京公网安备11010502063487号