【问题标题】:One slow ActiveMQ consumer causing other consumers to be slow一个缓慢的 ActiveMQ 消费者导致其他消费者变慢
【发布时间】:2014-07-11 17:25:24
【问题描述】:

我正在寻求有关一个奇怪问题的帮助,即队列中的慢速消费者会导致同一队列中的所有其他消费者开始以 30 秒的间隔消费消息。这就是所有消费者,但速度慢的消费者不会尽可能快地消费消息,而是在消费前等待一些神奇的 30 秒障碍。

我的应用程序的基本流程是这样的:

  1. 许多生产者将消息放置到单个队列中。消息可以有不同的 JMSXGroupID
  2. 许多消费者在单个队列上收听消息
  3. 作为标准做法,JMSXGroupID 分布在消费者之间
  4. 在某些时候,其中一个消费者变得很慢,无法快速处理消息
  5. 缓慢的消费者最终填充了代理上的预取缓冲区,AMQ 认识到它很慢(默认行为)
  6. 在那一点 - 或者某个“随机”但稍后关闭 - 除了慢速消费者之外的所有消费者都开始仅以相同的 30 秒间隔消费消息
  7. 如果缓慢的消费者再次变得快速,那么事情很快就会恢复正常运行,30 秒的障碍就会消失

我不知道是什么原因导致了这个问题,或者如何解决它,请帮忙。

更多背景和发现

  • 我已经成功地在 AMQ 5.8.0、5.9.0(最初发现问题的地方)和 5.9.1、全新安装和现有的操作管理安装以及不同的机器上可靠地重现了这个问题,一些 vm 和有些不是。所有 linux 安装、不同的操作系统和 java 版本。
  • 它似乎不受任何与预取相关的影响,即:将预取值从 1 更改为 10 到 1000 并没有阻止问题的发生
  • [red herring?] 在 amq 实例上启用调试日志会显示与定期检查可能过期的消息相关的日志。队列没有过期策略,所以我只能认为预定的 expireMessagesPeriod 时间只是唤醒 amq,然后它会向非慢速消费者发送消息。
  • 如果进入 30 秒模式,然后左转,然后再次进入,则分钟后的秒数始终相同,例如分钟后的 14 秒和 44 秒。这适用于所有消费者和托管这些消费者的所有机器。重新启动 amq 后,这些障碍点确实会发生变化。

【问题讨论】:

  • 创建一个单元测试并为 ActiveMQ 的问题打开一个 Jira
  • OK 就可以了。我认为这不是预期的行为吗?
  • issues.apache.org/jira/browse/AMQ-5200 - 创建此票证以涵盖这种确切情况(即使用组而不是选择器),以防它被认为比修复替代情况更重要

标签: performance jms activemq


【解决方案1】:

虽然不是严格意义上的问题解决方案,但进一步调查发现了此问题的根本原因。

TL;DR - 这是已知行为,不会在 Apollo 之前修复

更多详情

这最终是由maxPageSize 属性和AMQ 仅将选择标准应用于内存中的消息这一事实引起的。通常这些是消息选择器 (property = value),但在我的情况下它们是 JMSXGroupID=>Consumer 分配。

当队列接收到消息时,它们会被分页到内存中并放入一个集合(在源代码中名为 pagedInPendingDispatch)。为了发送消息,AMQ 将扫描这个消息列表并尝试找到一个接受它的消费者。这包括检查组 ID、消息选择器和预取缓冲区空间。对于我们的用例,我们没有使用消息选择器,而是使用了组。如果没有消费者可以接收消息,则将其留在集合中,并在下一次滴答时再次检查。

为了阻止pagedInPendingDispatch 集合耗尽所有可用资源,建议限制通过maxPageSize 属性配置的此队列的大小。这个属性实际上并不是一个最大值,它更多的是一个提示,在正常情况下,新消息到达是应该在内存中分页还是分页到磁盘。

有了这两条信息和一个慢消费者,最终pagedInPendingDispatch 集合中的所有消息最终只能被慢消费者消费,因此该集合被有效地阻塞并且没有其他消息被分派.这解释了为什么慢消费者不受 30 秒间隔的影响,它已经有 maxPageSize 消息等待传递。

这并不能解释为什么我看到非慢速消费者每 30 秒收到一次消息。事实证明,将消息分页到内存有两种模式,正常强制。 Normal 遵循上面概述的过程,其中集合的大小与maxPageSize 属性进行比较,但是,当强制执行时,消息总是被分页到内存中。此模式的存在允许您浏览不在内存中的消息。碰巧这种强制模式也被过期机制使用,以允许 AMQ 使不在内存中的消息过期。

所以我们现在拥有的是内存中的消息集合,这些消息都针对分派给同一个消费者,一个消费者不会接受它们,因为它很慢或被阻塞。我们还有大量消息等待交付给所有消费者。每expireMessagesPeriod 毫秒运行一个任务,强制将消息分页到内存中以检查它们是否应该过期。这会将这些消息添加到集合中的页面上,其中现在包含针对慢速消费者的 maxPageSize 消息和发往任何消费者的更多消息 N。这些消息会被传递。

QED。

参考文献

【讨论】:

    猜你喜欢
    • 2011-04-15
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    • 2012-03-11
    • 2016-05-16
    • 2016-06-08
    • 1970-01-01
    相关资源
    最近更新 更多