跳至主内容

2025年从经典镜像队列迁移到仲裁队列

·阅读16分钟
Aitor Perez
Aitor Perez

RabbitMQ 4 已经发布一段时间了,我们已经介绍了一些它相比前代 RabbitMQ 3.13 的优点。例如,改进的性能原生 AMQP 1.0,以及新的仲裁队列功能,这使得它与经典队列的功能趋于一致。

我们上次撰写关于 如何从经典镜像队列 (CMQ) 迁移到仲裁队列 (QQ) 的文章已经有一段时间了。如果您还不知道,CMQ 自 RabbitMQ 3.9 起已被弃用,并在 RabbitMQ 4.0 中被移除。今天我们将更详细地介绍仲裁队列,将其与 CMQ 进行比较,并提供高层迁移策略,以便彻底放弃 CMQ,转而使用 QQ,或 QQ 与经典队列 (CQ) 的组合。请注意,CQ 仍然得到很好的支持,被弃用和移除的是它们的镜像功能。

为什么选择仲裁队列?

镜像经典队列,又称经典镜像队列,又称 CMQ,是为了给经典队列 (CQ) 添加集群内数据复制功能而引入的。CQ 最初是作为一种非复制队列类型设计的,可追溯到 2006 年,也就是 RabbitMQ 开发的第一年。

大约在 2009 年,镜像功能增加了将数据复制到其他节点的能力。用于“镜像”数据的算法是内部开发的,并且对网络分区不是很健壮。更糟糕的是,CMQ 在某些故障场景下的行为有时不可预测,而且通常很难理解。甚至出现过 CMQ 丢失消息 的情况。

为了解决所有这些问题,并为 RabbitMQ 添加一种可靠、安全且可复制的队列类型,仲裁队列被设计并集成到 RabbitMQ 中。

仲裁队列 是一种从头开始设计的复制队列类型,基于 Raft 共识算法。仲裁队列的设计以数据安全为首要任务。所有 QQ 都有一个领导者和一些跟随者;在逻辑上,领导者和跟随者分布在 RabbitMQ 节点之间。当 QQ 领导者接收到一条消息时,它会在预写日志 (WAL) 中记录此操作,然后在本地 Raft 日志中将消息存储在磁盘上,并并行向跟随者发出复制命令,在收到大多数节点的确认后,再将确认发送回客户端。

与 CMQ 的一个关键区别是,复制部分是并行完成的,而 CMQ 使用链式复制算法。两者之间的另一个重要区别是:仲裁队列通过了更严格版本的 Jepsen 测试,而 CMQ 甚至连要求较低的原始版本都无法通过。

在领导者失败的情况下,最新的跟随者会启动投票过程,并选举出新的 QQ 领导者。新选出的领导者将恢复队列的操作。您可以在 GitHub 上了解有关 Raft 共识算法 的更多详细信息。

有了这些特性,QQ 就解决了 CMQ 的主要问题:数据安全性和故障场景的可预测性。此外,仲裁队列在许多工作负载下提供了 接近完整的功能对等性 和更高的吞吐量。

然而,QQ 并不适用于消息系统中存在的某些用例。例如:在 RPC(请求-回复)通信中使用的临时队列。

对于非常短生命周期的瞬时数据,使用仲裁队列是没有意义的,因为数据安全对于此类用例来说不是优先考虑的。例如,如果您的应用程序以“发送即忘”的方式发布消息,并且/或您的消费者应用程序不使用手动确认。对于这些用例,经典队列 **(不带镜像)** 是一个绝佳的选择。

从 CMQ 迁移到 QQ

考虑到这两种队列类型(包括存储级别)的不同性质,无法“就地”将现有的经典队列转换为仲裁队列。

但是,可以采用 蓝绿部署 进行迁移。这是一种策略,将应用程序从包含镜像经典队列的现有集群(称为“蓝色”集群)迁移到一个新集群(称为“绿色”集群),后者将使用仲裁队列来处理蓝色集群中所有被镜像的经典队列。

RabbitMQ 提供了工具来简化迁移。`rabbitmqadmin v2` 是一个基于 RabbitMQ Core Team at Broadcom 构建的 HTTP API 的 CLI 工具,它支持许多命令,可以简化迁移过程。

在深入细节之前,让我们先看看如何将使用镜像经典队列的现有 RabbitMQ 3.13.x 集群迁移到一个新的 4.1.x 集群,后者将为所有镜像队列使用仲裁队列。

高层迁移计划

蓝绿升级策略有一些在升级前必须满足的要求

  • 必须启用 RabbitMQ 队列联邦
  • 为了使队列联邦正常工作,蓝色(原始)集群必须能从绿色(新)集群访问
  • 绿色(新)RabbitMQ 版本必须运行 4.x 版本,最好是最新版本
  • 所有稳定的 功能标志 都必须在绿色(新)集群中启用

在满足先决条件后,迁移计划包括以下步骤

  1. 使用 rabbitmqadmin v2 从蓝色集群导出定义,并进行一些转换,以确保定义不包含新集群不支持的任何键(特别是 CMQ 镜像策略)
  2. 将定义导入绿色集群
  3. 配置两个集群之间的 队列联邦
  4. 将消费者迁移到绿色集群
  5. 将生产者迁移到绿色集群
  6. 监控 绿色集群的状态
  7. 关闭原始集群
  8. 从绿色集群中删除一些临时迁移策略

现在,让我们深入细节。

应用程序的注意事项

仲裁队列支持持久化镜像经典队列的所有功能。这意味着大多数应用程序可以在不进行任何更改的情况下迁移到新集群。对于那些显式指定队列类型的少数应用程序,可以使用一个特殊的 rabbitmq.conf 设置来放宽 RabbitMQ 节点在客户端尝试声明队列时执行的关键队列属性等效性检查。

功能比较矩阵 涵盖了仲裁队列与经典队列的区别。

现在是时候重新考虑某些应用程序是否真的需要使用复制队列了。例如,一个创建并绑定临时队列到扇出交换机,处理信息一段时间,并在断开连接后删除其队列的应用程序,将无法从复制队列类型(仲裁队列)提供的功能中受益,因为队列生命周期很短,特定于某个客户端,并且应用程序能够重新声明其拓扑。

如果某些队列不需要复制,请在继续之前从它们的策略中删除与经典队列镜像相关的键。这些键是

  • "ha-mode"
  • "ha-params"
  • "ha-promote-on-shutdown"
  • "ha-promote-on-failure"
  • "ha-sync-mode"
  • "ha-sync-batch-size"

这些非复制的经典队列将作为经典队列迁移到绿色集群,从而避免在不必要时使用仲裁队列。

详细迁移计划

此计划已在 RabbitMQ Blue 3.13.7 和 RabbitMQ Green 4.1.2 上进行了测试。TLS、mTLS 和纯 TCP 都经过了测试。CLI rabbitmqadmin v2 和 RabbitMQ 在所有测试的设置中都能正常工作。

从蓝色集群导出定义

在此步骤中,我们将备份所有 rabbitmq 对象(不包括消息)到一个 JSON 文件。所有用户名、vhost、队列、权限、绑定、策略、参数、交换机,一切都将被导出到一个 JSON 文件。可以应用转换来排除某些数据。这种转换功能将极大地帮助 CMQ 到 QQ 的迁移。

以下命令导出 RabbitMQ 的定义文件,并通过移除已弃用的 CMQ 策略键和 可选队列参数 来转换结果,将以前镜像的经典队列替换为仲裁队列。

任何应用了镜像 策略 的队列将被自动转换为定义(备份)文件中的仲裁队列。如果转换后策略变为空(因为只包含 CMQ 键),它也将被删除,因为 RabbitMQ 不支持导入空策略。

RabbitMQ 定义在所有集群节点之间共享,因此只需要在一个节点上运行此命令。

# Export definitions from the original cluster into a file and applies two transformations
# to remove all traces of classic mirrored queues
rabbitmqadmin --host blue definitions export --file blue.json -t prepare_for_quorum_queue_migration,drop_empty_policies

导入定义

在此步骤中,我们将把上一步的定义文件(CMQ 已转换为 QQ)“恢复”到新的“绿色”集群中。此命令的配置选项不多,是一个非常直接的步骤。

# Import definitions into the new (Green) cluster
rabbitmqadmin --host green definitions import --file ./blue.json

在绿色集群中配置联邦上游

在此步骤中,我们将配置 队列联邦。这些步骤至关重要,因为正是队列联邦链接会将任何现有消息从原始集群传输到新集群,从而允许在稍后迁移应用程序到新集群。

花些时间仔细阅读并提前准备命令。

创建联邦上游

每个 vhost,在 **绿色** 集群中创建一个联邦上游

rabbitmqadmin --host green federation declare_upstream_for_queues --name cmq-qq-migration --uri 'amqp://<federation-user>:<federation-password>@blue.rabbit'

其中 <federation-user> 是 **蓝色** RabbitMQ 中 **已存在的用户**。建议创建一个专用的联邦用户。

其中 <federation-password> 是用于在 **蓝色** RabbitMQ 中进行身份验证的联邦用户密码。

创建覆盖策略

此步骤创建 “覆盖”策略 以启用所有已匹配策略的队列的队列联邦。请注意,“覆盖”策略是 rabbitmqadmin v2 的概念,而不是 RabbitMQ HTTP API 的概念,因此此操作可以在 3.13.x 节点上执行。

在此步骤中,我们将配置 RabbitMQ 使用 联邦队列。当 **本地** 消费者请求消息 **并且** 本地队列为空时,联邦队列会将消息从上游集群传输过来。这将允许您无缝地将消费者应用程序迁移到绿色集群。

为每个策略创建覆盖策略以利用联邦上游

rabbitmqadmin --host green policies list
# => ┌──────┬─────────┬───────────────────────┬──────────┬──────────┬──────────────────┐
# => │ name │ vhost │ pattern │ apply_to │ priority │ definition │
# => ├──────┼─────────┼───────────────────────┼──────────┼──────────┼──────────────────┤
# => │ ha │ finance │ (?:^po$)|(?:.*\.dlx$) │ all │ 0 │ max-length: 100 │
# => │ │ │ │ │ │ queue-version: 2 │
# => │ │ │ │ │ │ │
# => └──────┴─────────┴───────────────────────┴──────────┴──────────┴──────────────────┘

rabbitmqadmin --host green policies declare_override --name ha --definition '{"federation-upstream": "cmq-qq-migration"}'

接下来,为任何未匹配现有策略的队列创建一个 覆盖/通用策略

rabbitmqadmin --host green policies declare_blanket --name cmq-qq-migration_blanket --apply-to queues --definition '{"federation-upstream": "cmq-qq-migration"}'

这将确保所有队列都在蓝色和绿色集群之间进行联邦。

验证联邦是否正常工作

一旦创建了策略,绿色集群中的联邦插件将创建到上游(蓝色)的链接(连接)。链接的存在确保在消费应用程序从蓝色迁移到绿色时,联邦队列已准备好将消息从上游(蓝色)传输到绿色集群。

rabbitmqadmin --host green federation list_all_links
# => ┌──────────────┬─────────┬──────────┬─────────────────────┬─────────┬───────┬──────────────────┬──────────────────────────────────┐
# => │ node │ vhost │ id │ uri │ status │ type │ upstream │ consumer_tag │
# => ├──────────────┼─────────┼──────────┼─────────────────────┼─────────┼───────┼──────────────────┼──────────────────────────────────┤
# => │ rabbit@green │ finance │ 8f0f0d8a │ amqps://blue.rabbit │ running │ queue │ cmq-qq-migration │ federation-link-cmq-qq-migration │
# => ├──────────────┼─────────┼──────────┼─────────────────────┼─────────┼───────┼──────────────────┼──────────────────────────────────┤
# => │ rabbit@green │ finance │ 01efa5b5 │ amqps://blue.rabbit │ running │ queue │ cmq-qq-migration │ federation-link-cmq-qq-migration │
# => ├──────────────┼─────────┼──────────┼─────────────────────┼─────────┼───────┼──────────────────┼──────────────────────────────────┤
# => │ rabbit@green │ finance │ 950faf11 │ amqps://blue.rabbit │ running │ queue │ cmq-qq-migration │ federation-link-cmq-qq-migration │
# => └──────────────┴─────────┴──────────┴─────────────────────┴─────────┴───────┴──────────────────┴──────────────────────────────────┘

准备迁移消费者

两个 RabbitMQ 集群(蓝色和绿色)都已准备好支持迁移。应用程序迁移的第一步是将消费者应用程序迁移到新的 RabbitMQ 集群(绿色)。

应用程序如何部署到绿色集群完全取决于您如何部署和运行 RabbitMQ 和应用程序。完成此步骤没有紧迫性或仓促性。请确保您的消费者应用程序按预期工作,然后再进行下一步。

准备迁移生产者

这是完成迁移的最后一步!迁移生产者包括停止生产者应用程序,让消费者通过队列联邦清空蓝色队列,然后启动绿色集群中的生产者应用程序。

如果您无法承担生产者应用程序停止直到消费者清空队列的情况,那么有一个特殊场景。这可能是因为您的使用场景涉及非常长的积压队列和缓慢的消费者。在这种特殊情况下,除了设置队列联邦之外,还可以考虑声明一个或多个 shovel,在重新部署生产者应用程序到绿色集群之前,用于将消息从蓝色移动到绿色。

迁移后的清理

在确认迁移成功完成并且您的应用程序运行正常后,请清理为迁移目的声明的策略以及绿色集群中的联邦上游。

删除临时策略

前面过程中创建的覆盖策略都将以 override. 作为前缀。在本指南中,通用策略的名称是 cmq-qq-migration_blanket

rabbitmqadmin --host green policies list
# => ┌──────────────────────────┬─────────┬───────────────────────┬──────────┬──────────┬─────────────────────────────────────────┐
# => │ name │ vhost │ pattern │ apply_to │ priority │ definition │
# => ├──────────────────────────┼─────────┼───────────────────────┼──────────┼──────────┼─────────────────────────────────────────┤
# => │ cmq-qq-migration_blanket │ finance │ .* │ queues │ -21 │ federation-upstream: "cmq-qq-migration" │
# => │ │ │ │ │ │ │
# => ├──────────────────────────┼─────────┼───────────────────────┼──────────┼──────────┼─────────────────────────────────────────┤
# => │ ha │ finance │ (?:^po$)|(?:.*\.dlx$) │ all │ 0 │ max-length: 100 │
# => │ │ │ │ │ │ queue-version: 2 │
# => │ │ │ │ │ │ │
# => ├──────────────────────────┼─────────┼───────────────────────┼──────────┼──────────┼─────────────────────────────────────────┤
# => │ overrides.ha │ finance │ (?:^po$)|(?:.*\.dlx$) │ all │ 100 │ federation-upstream: "cmq-qq-migration" │
# => │ │ │ │ │ │ max-length: 100 │
# => │ │ │ │ │ │ queue-version: 2 │
# => │ │ │ │ │ │ │
# => └──────────────────────────┴─────────┴───────────────────────┴──────────┴──────────┴─────────────────────────────────────────┘

rabbitmqadmin --host green policies delete --name cmq-qq-migration_blanket
rabbitmqadmin --host green policies delete --name overrides.ha

接下来,删除用于迁移消息的联邦上游

rabbitmqadmin --host green federation delete_upstream --name cmq-qq-migration

在开发环境中测试迁移

此迁移乍看起来可能令人生畏。Team RabbitMQ 对不同的场景和不同的队列功能组合进行了广泛的测试,然而,没有什么比亲自在您自己的环境中尝试更能增加信心了!

因此,强烈建议在开发或暂存环境中测试所有迁移命令和计划。有时,让您自己的应用程序模拟生产环境中的负载是很困难的。对于这种情况,RabbitMQ Perf Test 是模拟工作负载和测试特定 RabbitMQ 功能的一个绝佳替代方案。

例如,要模拟一个生产者以 30 msg/s 的速率向交换机 inc 发布消息,路由键为 bills,您可以使用以下 perf-test 命令

java -jar perf-test.jar \
-y 0 -x 1 -c 10 -p -qq \
--rate 30 -e inc \
--routing-key 'bills' \
--uri "amqp://myuser:mypass@blue.rabbit.example.com"

所有 perf-test 选项均在 Perf Test 文档 及其帮助命令中有所记载。

java -jar perf-test.jar --help

迁移后清单

完成迁移后,以下列表可以帮助您仔细检查迁移是否成功。请随时添加任何在您的环境中看起来有意义的其他项目。

  • 所有消费者应用程序都已连接到绿色(新)RabbitMQ 集群
  • 所有生产者应用程序都已连接到绿色(新)RabbitMQ 集群
  • 临时策略不存在
  • 联邦上游不存在
  • RabbitMQ 没有 触发警报
  • 所有 指标 都在其典型范围内

迁移陷阱

TLS

rabbitmqadmin v2 支持 TLS 启用的连接。但是,它要求 受信任的 CA 包含在系统受信任的 CA 中。

如何将受信任的 CA 添加到您的系统证书链中,因操作系统而异。以下链接不是完整的参考,而是方便大多数常用系统使用的

一旦 CA 被添加到操作系统级别的受信任证书列表中,它们就可以与 rabbitmqadmin 一起使用 PEM 格式的捆绑文件。例如

rabbitmqadmin --use-tls --tls-ca-cert-file /path/to/your/chained_ca_certificate.pem queues list

如果您的 RabbitMQ 配置为使用双向 对等验证(**mTLS**),那么 rabbitmqadmin 也需要提供客户端证书和密钥对。

例如:

rabbitmqadmin --use-tls --tls-ca-cert-file /path/to/your/chained_ca_certificate.pem \
--tls-cert-file /path/to/your/client_certificate.pem \
--tls-key-file /path/to/your/client_key.pem \
queues list

或者,由于将所有 TLS 选项添加到每个命令可能会很麻烦,因此可以将所有 TLS 选项、主机名、端口和凭据配置到 rabbitmqadmin 配置文件中。rabbitmqadmin 的配置文件是 TOML 格式,除了“node”别名之外,它还接受一些选项。例如

[blue]
hostname = "blue.rabbit"
tls = true
ca_certificate_bundle_path = "/path/to/your/chained_ca_certificate.pem"
client_certificate_file_path = "/path/to/your/client_certificate.pem"
client_private_key_file_path = "/path/to/your/client_key.pem"
port = 32795

[green]
hostname = "green.rabbit"
port = 32811
tls = true
ca_certificate_bundle_path = "/path/to/your/chained_ca_certificate.pem"
client_certificate_file_path = "/path/to/your/client_certificate.pem"
client_private_key_file_path = "/path/to/your/client_key.pem"

将上面的配置与 --config--node 一起使用。例如 rabbitmqadmin --config rabbitmqadmin.toml --node blue queues list

结论

仲裁队列 (QQ) 是 RabbitMQ 中数据安全的首选队列类型。它们提供可预测的故障转移行为和 比经典镜像队列 (CMQ) 更高的吞吐量。仲裁队列持续接收更新、性能改进和错误修复,而经典镜像队列在 3.13 版本处于支持维护状态,并在 RabbitMQ 4 版本中完全移除。经典队列(不带镜像)仍然是一种有效且受支持的队列类型。经典队列仍然适合某些用例,例如:RPC 模式。或任何不需要高可用性的用例。

借助新一代的 rabbitmqadmin,从镜像经典队列迁移到仲裁队列,同时升级到最新的 支持的 RabbitMQ 版本系列,现在比以往任何时候都更容易。

© . This site is unofficial and not affiliated with VMware.