RabbitMQ-在一个应用程序进程中为单个队列创建多个使用者是一个好习惯

时间:2017-07-17 08:48:03

标签: java multithreading rabbitmq

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

来自队列的消息是巨大的(一个生成行为的数百万条消息)所以我想第一个代码作者正试图做一些让消费更快的消息。

我正在尝试找到一些讨论此事的帖子,但我找不到一个非常确定的答案。

到目前为止我得到的是:

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

    所以

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

    2. ack的操作可以在不同的频道中进行,我不太确定这会有更好的表现。

    3. 由于更多频道消耗更多系统资源我不知道这种做法是否合适?

1 个答案:

答案 0 :(得分:0)

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

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

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

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

  3. 现在,我认为这个问题开始有点落伍了:

      

    来自队列的消息是巨大的(一个消息是数百万条消息)   单一生产行为)所以我想第一个代码是作者   试图做点什么来加快消费。

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

    此外,队列中任何时候的平均项目数应接近零。产能过剩通常是一个好主意,这样你就不会遇到消息开始在队列中累积的不稳定情况(队列最终看起来像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. 同样,如果您更喜欢使用消费者,一般来说,跨渠道分享消费者是一个坏主意。每个消费者都应该拥有自己的渠道。