【问题标题】:RabbitMQ-Is it a good practice to create multiple consumers for a single queue in one application processRabbitMQ-在一个应用程序进程中为单个队列创建多个消费者是一种好习惯吗
【发布时间】:2017-12-21 17:18:35
【问题描述】:

我刚刚使用了一个由 RabbitMQ 支持的新项目,并且在应用程序启动时创建了多个消费者实例来监听同一个队列。但是,它们与不同的频道共享相同的连接。

来自队列的消息是海量的(单个生产行为有数百万条消息),所以我猜第一个代码作者正在尝试做一些事情来加快消费速度。

我试图找到一些讨论这个的帖子,但我找不到一个非常确定的答案。

到目前为止我得到的是:

  1. 每个通道都有一个单独的调度线程
  2. 同一通道上的操作命令即使在多线程中调用也会被序列化

所以

  1. 创建多个消费者,因此多个通道将具有多个调度线程,但我认为它不会为消息调度提供更好的性能,因为单个线程的调度应该远远不够。

    李>
  2. ack 的操作会在不同的通道中被瘫痪,我不太确定这会带来更好的性能。

由于更多的频道消耗更多的系统资源,我想知道这种做法好吗?

【问题讨论】:

    标签: java multithreading rabbitmq


    【解决方案1】:

    这里似乎发生了一些事情,所以让我们尝试从整体的角度来看这个场景。

    对于初学者,听起来这段代码的原始设计者了解了一些关于 RabbitMQ 的基础知识(或者通过反复试验学到了一些东西),但可能无法将所有部分组合在一起 - 希望我能提供帮助。

    1. RabbitMQ 连接实际上是 AMQP-over-TCP 连接(因此位于 OSI model 的会话层附近)。 TCP 连接应该被打开和使用,直到某种网络中断或应用程序关闭关闭它们(因此,AMQP 在防火墙和其他智能网络设备方面存在问题)。将单个 TCP 连接用于单个逻辑进程的消息处理活动是一个好主意,因为创建和销毁 TCP 连接对于计算机来说通常是一个昂贵的过程,这会导致

    2. RabbitMQ 通道用于在 AMQP-Over-TCP 连接中多路复用通信流(并在 AMQP Protocol Spec 中定义)。他们所做的只是指定一个整数值(我不记得字节数,但无论如何都没关系),用于在 TCP 连接上作为后续命令或响应的开头。 大多数 AMQP 操作是特定于通道的。出于更高级别操作的目的,通道被视为类似于连接,因为它们是应用程序级别的构造。

    现在,我认为问题开始偏离轨道的地方是:

    队列中的消息是海量的(一百万条消息 单一生产行为)所以我猜第一个代码作者是 尝试做一些事情来加快消费。

    关于使用队列的系统的一个基本假设是消息的消耗速度与它们产生的速度大致相同。队列的存在是为了缓冲不均衡的生产活动。队列如何工作的数学和统计数据非常有趣,并且假设消息的生成是为了响应一些现实世界的刺激,您的系统几乎可以保证以可预测的方式运行。 因此,您的设计目标是确保有足够的消费者来处理产生的消息,并根据需要响应不断变化的条件。您的目标不应该是“加速”消费者(除非他们有一些特定问题),而是要有足够的消费者来处理总负载。

    此外,队列中的平均项目数在任何时候都应该接近于零。容量过剩通常是个好主意,这样您就不会遇到消息开始在队列中累积的不稳定情况(并且队列最终看起来像Stack Overflow Close Vote Queue)。

    这使我们试图回答您的基本问题,这似乎涉及 Java 客户端的线程和可能的详细实现,我很乐意承认我没有使用过(我是一个 .NET 人)。

    以下是您的软件的一些设计指南:

    1. 确保单个线程使用不超过一个通道。
    2. 每个逻辑消费进程使用一个 TCP 连接。
    3. 平衡单个物理机上的逻辑进程数量,以免资源争用成为问题(您不希望消耗计算机资源)。
    4. 尝试使用BASIC.GET 而不是基于推送的消费者。在实践中使用消费者很困难,并且在协议级别上没有性能优势超过BASIC.GET。 注意我不知道 Java 库是否以不同的方式实现了这些,从而导致性能差异 - 已知会发生奇怪的事情。
    5. 如果您确实使用消费者,请确保预取设置为 0(禁用),并且如果可靠处理很重要(大多数应用程序需要可靠处理),则将 AutoAck 设置为 false。除此之外,请确保您在处理完成后确认消息!
    6. 定期重新启动您的消费线程、通道和处理器 - 或执行BASIC.Recover。有一定程度的随机性会导致未确认的消息随着时间的推移而累积,这将解决它。
    7. 同样,如果您更喜欢使用消费者,一般来说跨渠道共享消费者是个坏主意。每个消费者都应该有自己的频道。

    【讨论】:

    • 感谢您的回答,我使用了一些较新的 MQ,例如 kafka,所以我想知道单个进程中的更多消费者确实做得更好,因为实际的工作人员是线程。如果我放置了足够多的线程,那么单个进程中的更多消费者(通道)真的有帮助吗?
    • 从逻辑上看,进程和线程都增加了并行度,更高的并行度通常会导致作业在队列中花费的时间更少。消费者只是一个管道,因此线程可以获取消息。
    • RabbitMQ 文档明确反对您支持 BASIC.GET 的建议。因此,如果没有充分的理由,我会警告人们不要在 #4 中提出建议。 rabbitmq.com/consumers.html#fetching
    猜你喜欢
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多