【问题标题】:Horizontal scaling of consumers when the publisher provides sequenced messages当发布者提供有序消息时消费者的水平缩放
【发布时间】:2018-07-25 06:36:44
【问题描述】:

在分布式面向服务的架构中,假设我有一个生产者,它使用 RMQ 向消费者发送消息。

然后我们决定通过添加更多消费者来横向扩展我们架构的消费部分,但我们面临一些限制。

发布者在它发送的每条消息中都提供一个序列号。消费者根据消息的序列号处理消息,这一点非常重要。

每次处理给定资源时,比如说 A,发布者将发送 RMQ 消息,上面写着“嘿,让我们为 A 做序列 1”,然后“嘿,让我们为 A 做序列 2”等等。

例如,如果发布者为 A 提供 3 条消息,序列为 1、2 和 3,并且这 3 条消息被分发到我们消费者的 3 个不同实例。序列 2 的消息被重新排队,直到序列 1 处理好,序列 3 也一样。

最后,消息都得到了很好的处理,但经过多次重试!这会导致我们的系统出现一些延迟,因为如果我们有 100 个序列要消耗,我们会重试多次。

一种可能的解决方案是确保给定资源的每组序列都必须由同一消费者处理。但是我们如何才能做到这一点呢?

我怎样才能避免重新排队,以确保我们的消费者的每个实例总是得到有序的给定资源的消息?

【问题讨论】:

    标签: asynchronous rabbitmq microservices


    【解决方案1】:

    我不熟悉 RMQ,但我会尽力提供帮助。

    对我来说,您似乎希望以每个消费者专用于单一资源的方式扩展您的消费者。这是必要的,因为您在单个资源的序列之间存在依赖关系,因此在多个消费者之间分配工作没有意义。

    我有使用 Kafka 的经验,您可以在那里使用所谓的“主题”向其发送消息,并让消费者专门处理一个主题,从那里获取工作项。

    不确定这是否可以在 RMQ 上实现。

    如果这不是您的架构中的一个选项,我会尝试以下方法: 通过首先检查消息有效负载是否与该资源相关,将单个使用者专用于资源。如果是,则执行工作,如果不是,则重新排队。

    【讨论】:

      【解决方案2】:

      尝试以下方法:

      • 创建topic exchange
      • 让您的生产者向其发送消息 每个资源的主题:主题A 用于资源A,主题B 用于 资源B 等等。
      • 让 1 个消费者收听 1 个主题。为每个使用持久队列 消费者,因此队列将在消费者重启后继续存在。如果你有 生产者 -> 一个交换 -> 1 个队列 -> 1 个消费者消息路径, 保证消息的顺序,请参阅RabbitMQ broker semantics 了解详情。
      • 让你的消费者得到1 message at a timeack只有当 处理完毕。

      这有望为您提供所需的顺序处理,并且您不需要重新排队消息。

      请注意,如果您的消费者在完成处理任务和acking 消息之间死亡,则可能会收到两次相同的消息。

      【讨论】:

      • 这可能是最接近相关实现的 OP,但还需要使解决方案能够抵御数据丢失和“死胡同”数据。 (询问如果队列消费者崩溃会发生什么,并查看解决方案的作用。)OP 可能会认为 RabbitMQ 是错误的工具,或者该解决方案需要除 RabbitMQ 之外的其他工具。
      【解决方案3】:

      RabbitMQ 只是一个路由消息的代理。你不应该用它来管理你的业务,因为你会有很多复杂的路由规则。

      我个人用一个消费者解决了这个问题。它的目标是侦听队列,根据业务规则将事件推送到堆栈中。如果您仍然需要扩大消费者的数量,您可以使用反应式架构模式,让您协调所有分叉实例之间的负载平衡。

      另一个使用 RabbitMQ 的解决方案是设置消息的优先级并创建消费者监听特定的优先级。 https://www.rabbitmq.com/priority.html

      如果这两种方案仍然不能解决你的问题,你可以通过消费者设置一个队列,并在你重新排队消息时发送相应队列中的序列。使用这个简单的解决方案,您将始终确保同一消费者读取给定消息,但您将失去负载平衡的好处。

      【讨论】:

        【解决方案4】:

        看起来您希望您的消息按资源 ID 进行分区。

        有一个插件:https://github.com/rabbitmq/rabbitmq-sharding 它将通过对消息路由键应用一致的散列将队列划分为多个分片。据我了解,这是通过Consistent Hash Exchange 完成的。

        您可以使用您的资源 id 作为路由键,因此 同一资源的消息将最终在同一个分片中。每个消费者将处理来自一个分片的消息,并且它们应该进入发布顺序。因此,您应该会按顺序看到相同资源的消息。

        【讨论】:

          猜你喜欢
          • 2019-09-07
          • 2019-05-20
          • 2016-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-25
          • 2016-06-08
          • 2021-03-17
          相关资源
          最近更新 更多