【问题标题】:RabbitMQ change queue parameters on a production systemRabbitMQ 在生产系统上更改队列参数
【发布时间】:2014-10-06 02:32:16
【问题描述】:

我在面向服务的架构中使用 RabbitMQ 作为消息队列,其中许多单独的 Web 服务发布绑定到 RabbitMQ 队列的消息。这些队列依次由执行后台工作的各种消费者订阅; RabbitMQ 的一个非常普通的用例。

现在我想更改一些队列参数(具体来说,我想将队列绑定到具有特定路由键的新死信交换)。我的问题是,在生产系统上进行这种更改是有问题的,原因有几个。

在生产系统中,在不丢失消息的情况下过渡到这些新队列的最佳方式是什么?

我已经考虑了从版本控制队列名称到使用新设置创建新虚拟主机到进行所有更改的所有事情。

以下是我面临的一些问题:

  1. 因为 RabbitMQ 队列是幂等的,不同的 Web 服务在发布到它们之前已经声明了队列(以防它们不存在)。一旦更改了队列参数(但保持相同的路由键),队列声明失败,RabbitMQ 关闭通道。

  2. 我希望在更改队列时不会丢失消息(这里我计划订阅一个独占的消费者来保存消息然后重新发布到新队列)。

  3. 不同的发布者和消费者群之间的一般协调(或者,甚至更好的一种避免需要协调它们的方法)。

【问题讨论】:

    标签: rabbitmq pika bunny


    【解决方案1】:

    可以在运行时添加和删除队列绑定,而不会对客户端产生任何影响,除非客户端手动修改绑定。因此,如果您的问题只是关于绑定的问题,只需通过 CLI 或 Web 管理面板更改它们,然后跳过下面写的内容。

    进行不兼容的更改是一个常见问题,尤其是在异构环境中,尤其是当多个应用程序尝试以自己的方式(使用其特定设置)声明相同实体时。在多个应用程序中同时更改队列声明没有简单的方法,这在很大程度上取决于整个工作流程的组织方式、您的应用程序的重要性、您的基础架构等。

    又快又脏的方式:

    虽然发布者不处理队列声明和绑定(至少他们不应该这样做),但您可以专注于消费者。在 try-except 块中包装队列声明可能是快速而肮脏的选择。此外,大多数项目,甚至很多项目都可以在短暂的停机时间内幸存下来,因此您可以在一个 shell 中阻止 rabbitmq 用户,根据需要更改队列(创建新的并让您的消费者使用它而不是旧的),然后取消阻止用户并让消费者像之前(您的工人在主管或监控之下,对吗?)。然后手动将消息从旧队列迁移到新队列。

    快速安全的解决方案:

    这有点棘手,它基于如何将消息从一个队列迁移到单个 vhost 中的另一个队列。整个解决方案在单个 vhost 中工作,但您要修改的每个队列都需要额外的队列。在源队列上设置Dead Letter Exchanges 并将其指向将过期消息路由到新的目标队列。然后将Per-Queue Message TTL 应用于源队列,设置x-message-ttl=0(设置为最小值,请参阅No Queueing at all 关于立即交付的说明)。这两个操作都可以通过 CLI 或管理面板完成,并且可以在已声明的队列上完成。通过这种方式,您的发布者可以像往常一样发布消息,甚至老消费者也可以首次按预期工作,但同时新消费者可以从新队列中消费,该队列可以手动或以其他方式使用新参数预先声明。

    请注意,在具有大量消息数量和大量消息流的队列上,存在满足流控制限制的一些风险,尤其是在您的服务器几乎利用了所有资源的情况下。

    更复杂但更安全的方法(适用于整个消息工作流逻辑发生变化的情况):

    对应用程序进行所有必要的更改并与现有代码库并行运行新的代码库,但在不同的 RabbitMQ 虚拟主机上(甚至使用单独的服务器,这取决于您的应用程序负载和硬件)。实际上,可能可以在同一个虚拟主机上运行,​​但更改交换和队列名称,但它甚至听起来并不好,即使是书面形式也有异味。设置新应用程序后,将它们与旧应用程序切换并运行消息从旧队列迁移到新应用程序(或让旧系统清空队列)。它保证以最少的停机时间进行无缝迁移。如果您的部署自动化,整个过程不会花费太多精力。

    P.S.:在以上任何情况下,如果可以的话,让老消费者清空队列,这样你就不需要手动迁移消息了。

    更新:

    您可能会发现Shovel plugin 非常有用,尤其是Dynamic Shovels 在交换和队列之间移动消息,甚至在不同的虚拟主机和服务器之间移动消息。这是在队列/交换之间迁移消息的最快和最安全的方式。

    【讨论】:

    • 感谢您的回答。 vhost 解决方案对我来说也是最干净的,但它引入了一个问题:所有分布式发布者都必须跟踪他们发布的位置,并在每次我们进行更改时进行相应的更新。有没有一种简单的方法可以让它们指向同一个地方,而我们可以将它路由到正确的 Vhost 的其他地方?如果可以避免的话,我认为出版商不必担心这些细节。但也许这更像是一个系统管理员问题而不是 RabbitMQ 问题。
    • 通常 vhost 是可配置的选项(或者至少应该是),所以改变它应该不是问题。请注意,如果您不想(或您负担不起)停机时间,只需并行运行新的发布者和消费者,然后停止原来的将消息从旧虚拟主机迁移到新虚拟主机。但是,如果可以的话,让您的应用在第一阶段队列声明失败后仍然存在,然后将新的更改应用于生产者和消费者。
    • 我添加了一个解决方案(快速和安全的解决方案),它可以方便地对队列声明进行热更改,例如,将其设置为持久或自动删除或独占等。但是在遵循这种方式之前,请确保您了解自己在做什么。
    • 如果您不确定任何情况,您可以通过在 rabbitmq 用户组 - groups.google.com/forum/#!forum/rabbitmq-discuss 中提出相同的问题来仔细检查解决方案,并指向我们讨论的链接。
    • 我用铲子插件说明更新了我的答案,希望对某人有所帮助。
    猜你喜欢
    • 2017-03-01
    • 2011-08-14
    • 2012-10-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2020-09-12
    • 2011-02-23
    • 1970-01-01
    相关资源
    最近更新 更多