一个简单但有效的 RabbitMQ 代理迁移策略

兔MQ

RabbitMQ 是一款了不起的软件,已成为许多知名公司的行业标准。 我们将它用于异步服务到服务的通信。 消息首先由 Web 服务推送到队列,然后由后端工作人员处理。 这让我们可以解耦事件创建和处理。 这些事件包括付款、用户注册、文档生成等。

在 Nord Security,我有幸使用这项技术工作了 4 年多,涉及多种编程语言和许多项目,所以我开始了解并喜欢它。 最近,我和我的团队的任务是将我们的主要 RabbitMQ 代理实例迁移到一个新的和更新的实例。 我想分享一下我们是怎样做到的。

过时

RabbitMQ 消息代理已被证明是一款可靠且有弹性的软件。 但随着时间的推移,必须更新软件以保持高性能和安全。 不幸的是,我们的主要 RabbitMQ 代理服务器太长时间没有更新,无法对系统应用新的重要升级。

以下是旧版 RabbitMQ 的主要问题:

  • 新的 Debian OS 版本与旧的 RabbitMQ 不兼容;
  • 不再支持 RabbitMQ 软件版本;
  • 无法应用新的错误修复和安全更新;
  • 无法安装重要的新功能和改进。

此外,我们的许多服务都依赖于这个 RabbitMQ 代理实例来工作,因此任何中断都可能意味着我们的业务非常严重的停机时间。

因此,我们需要将所有队列从旧代理迁移到一个新的、闪亮的。 但这说起来容易做起来难。 这个代理中有超过 200 个队列,来自不同服务的消费者数量相同。

我们需要一个能够实现零消息丢失的无缝过渡的解决方案,因为我们的关键业务系统依赖于消息队列来执行它们的任务。

联合队列

对我们来说幸运的是,RabbitMQ 有一个称为联合队列的功能。 这是一种将消息从一个代理传递到另一个代理的方法,而不会在此过程中复制或丢失消息。 当上游队列没有消费者时,它通过将消息从上游代理队列移动到下游来设法做到这一点。

要访问队列联合功能,我们需要在 RabbitMQ 实例上安装联合插件。 您可以在官方 rabbitmq 文档中找到有关怎样执行此操作的信息。

战略

我们通过使用 RabbitMQ 虚拟主机将队列划分为逻辑域,因此单独迁移每个虚拟主机是有意义的。 我们提出了这个队列迁移策略:

  1. 设置从旧代理到新代理的队列联合;
  2. 将消费者迁移到新的代理;
  3. 将发布者迁移到新的代理;
  4. 禁用队列联合并删除剩余队列。

从理论上讲,这个过程将允许我们单独迁移所有队列而无需任何停机,因为一旦消费者迁移到新代理,所有消息都会简单地移动到新代理。

迁移过程

首先,我们对所有队列及其消费者进行了审计。 之后,我们决定先迁移哪些队列并开始建立队列联合。 我将引导您完成我们在其中一个队列中所采取的步骤。

假设我们要迁移一个名为 order.events.nordvpn-affiliate.process-orders 的队列。 它位于 nordvpn_affiliate vhost 下,并使用路由键 order.event.created 绑定到订单交换。 我们正在使用主题交换类型。 这个队列由 nordvpn-affiliate 微服务消费者使用,它处理通过附属渠道进行的购买。

我们在 new-rabbit.nordvpn.com 上设置了一个新的 RabbitMQ 代理。 要将队列联合设置为旧的下游代理 old-rabbit.nordvpn.com,我们必须 ssh 进入新的代理服务器并在终端中运行以下命令:

rabbitmqctl set_parameter --vhost "nordvpn_affiliate" federation-upstream old-nordvpn-affiliate '{"uri":"amqp://user:[email protected]:5673/nordvpn_affiliate"}'

这将为 nordvpn_affiliate 虚拟主机在上游建立联合。 您可以使用 RabbitMQ 管理面板检查所有已配置的联合上游。 我们的新联合虚拟主机如下所示:

RabbitMQ 联合上游面板

接下来,我们必须设置队列联合策略并覆盖默认策略。 我们运行这个命令:

rabbitmqctl set_policy --vhost "nordvpn_affiliate" old-nordvpn-affiliate-federation '.*' '{"federation-upstream-set":"all"}' --apply-to queues --priority 1

这将为 nordvpn_affiliate vhost 中的所有队列设置队列联合,优先级为 1,优先于其他策略。 接下来,我们检查策略是否设置正确。

RabbitMQ 策略面板

随着队列联合的建立,我们现在可以迁移消费者了。 我们所有的消费者都会在启动时自动创建和绑定队列。 如果他们没有,我们需要手动在新代理中创建队列,或者通过从旧代理导出配置并将其导入新代理。

我们更改消费者中的 RabbitMQ 代理 URL 并部署新配置。 部署后,它立即开始使用新联合队列中的消息。 没有消息丢失,它们在队列中保持顺序:

RabbitMQ 消费者面板

我们对 nordvpn_affiliate vhost 中的所有队列重复此过程。 在迁移所有消费者之后,我们也迁移发布者。

现在剩下的就是删除队列联合并从旧的 RabbitMQ 代理中删除队列。 而已!

概括

迁移软件基础设施很少有乐趣。 但是我们发现了一种使用联合队列将队列从一个 RabbitMQ 代理迁移到另一个的简单可靠的方法。 我们已经通过这种方式将很多队列迁移到了新的 RabbitMQ 代理,没有出现重大问题,很快我们将完全迁移所有队列。