You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ActiveMQ Artemis高负载下消息延迟及流控相关问题求助

问题描述

我们基于ActiveMQ Artemis 2.27.1(单节点集群,使用Core协议)搭建了应用套件,流程如下:

  • 应用A向REQUEST Q发送消息后,在对应REPLY Q上等待匹配关联ID的响应消息
  • 应用B监听并消费REQUEST Q的消息,处理完成后立即向REPLY Q发送匹配关联ID的响应消息,由应用A接收

低负载下运行正常,但**峰值负载(消息大小1k至5mb)**时出现以下问题:

  1. 应用A发送消息延迟严重(客户端发送到Artemis接收延迟超10秒)
  2. 应用A接收REPLY Q消息也存在大幅延迟

关键日志信息

消费者流控相关日志

DEBUG org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl {id=2, filter=FilterImpl sfilterString=JMSCorrelationID = 'ID:xys123etcetc', binding=LocalQueueBinding [address=REPLYQ1] queue=QueueImpl[name=REPLYQ1], postOfficeImpl=PostOfficeImpl [server=ActiveMQServerImpl::name=artemis-0], temp=false, filter=null, name=REPLYQ1, ClusterName=xxxxxx is busy for lack of credits. Current credits=0
DEBUG org.apache.activemq.artemis.core.server.impl.QueueImpl  QueueImpl[name=REPLYQ1], postOfficeImpl=PostOfficeImpl [server=ActiveMQServerImpl::name=artemis-0], temp=false :: All the consumers were busy, giving up now 

流控信用日志

FlowControl::Received 1048576 credits, previous value = 0, currentValue = 1048576.

目标地址阻塞日志

org.apache.core.client : AMQ212054: Destination address=REPLYQ1 is blocked. If the system is configured to block make sure you consume messages on this configuration. 

延迟示例日志

(App日志)

2023-05-15 15:00:08.354 TRACE [App1] : sendRegularMessage::ClientMessageImpl[messageID=0, durable=true, address=REQUESTQ1.......
2023-05-15 15:00:08.354 TRACE [App1] : RemotingConnectionID=xxxxxxx Sending blocking PACKET (SessionSendMessage), channelID=11, responseAsync=true, requiresResponse=true......  address=REQUESTQ1.

(Artemis日志)

2023-05-15 15:00:22.317 DEBUG [org.apache.activemq.artemis.core.server.impl.ServerSessionImpl] Routing result for CoreMessage.......

已尝试操作

  • 在地址配置中设置consumerWindowSize=-1或极大值,无改善
  • 调整consumerWindowSize、producerWindowSize、tcpSendBuffer、tcpReceiveBuffer等参数,问题仍存在

更新补充

部分无信用不足日志的场景下,REPLY Q上基于JMS关联ID消费的消息仍存在5秒左右延迟,日志显示消息到达Artemis后,经过5秒才完成消费者匹配并投递。

现需明确:

  1. 流控机制触发的根本原因
  2. 流控的禁用/优化方法
  3. 整体延迟问题的解决方案

解决方案分析

一、流控触发原因

  1. 消费者信用耗尽:应用A在REPLY Q上的消费者使用了基于JMSCorrelationID的过滤条件,Artemis会为每个带过滤的消费者维护独立的信用额度。当大消息(如5mb)占满信用窗口后,后续消息无法投递,触发“lack of credits”日志。
  2. 地址阻塞连锁反应:REPLY Q的消费者信用耗尽后,队列消息堆积,达到地址的阻塞阈值(默认是内存/磁盘占满触发),导致应用B向REPLY Q发送消息时被阻塞,进一步加剧整体延迟。
  3. 1048576信用值的来源:这个值是Artemis客户端默认的consumerWindowSize(1MB),即使在Broker端配置了consumerWindowSize,客户端如果没有显式配置会使用默认值,这也是修改Broker配置无效的核心原因。

二、流控优化/调整方法

1. 客户端显式配置消费窗口

必须在应用A的Core客户端连接配置中显式设置consumerWindowSize=-1(禁用消费流控),而非仅在Broker端配置:

// Core客户端示例代码
ClientSessionFactory factory = ActiveMQClient.createClientSessionFactory(
        new TransportConfiguration(NettyConnectorFactory.class.getName())
);
ClientSession session = factory.createSession();
// 最后一个参数设为-1即禁用消费流控
ClientConsumer consumer = session.createConsumer("REPLYQ1", "JMSCorrelationID = 'xxx'", false, true, true, -1);

或在客户端连接URL中添加参数:

tcp://artemis-host:61616?consumerWindowSize=-1

2. 调整地址阻塞策略

修改Broker的broker.xml中REPLYQ1对应的地址设置,调整阻塞阈值或临时禁用阻塞(生产环境建议调整阈值而非直接禁用):

<address-settings>
    <address-setting match="REPLYQ1">
        <!-- 禁用地址阻塞(仅临时调试用) -->
        <block-on-disk-full>false</block-on-disk-full>
        <block-on-memory-full>false</block-on-memory-full>
        <!-- 或调整内存阈值,比如设置为80%内存占用时触发 -->
        <memory-high-watermark>80</memory-high-watermark>
        <memory-low-watermark>50</memory-low-watermark>
    </address-setting>
</address-settings>

3. 优化带过滤的消费者性能

对于基于JMSCorrelationID的过滤消费,默认遍历队列匹配消息的方式在大负载下效率低下,可通过以下方式优化:

  • 使用临时队列代替固定REPLY Q:应用A发送请求时创建专属临时队列作为回复地址,避免全局REPLY Q的过滤匹配开销
  • 启用队列索引:在Broker端为JMSCorrelationID创建索引,加速过滤匹配:
<address-settings>
    <address-setting match="REPLYQ1">
        <indexing-enabled>true</indexing-enabled>
        <indexed-properties>JMSCorrelationID</indexed-properties>
    </address-setting>
</address-settings>

三、延迟问题根因与解决

  1. 发送延迟:应用B发送到REPLY Q被阻塞,导致应用A的请求消息在REQUEST Q堆积,Artemis处理路由延迟。解决上述流控和阻塞问题后,发送延迟会缓解。
  2. 消费匹配延迟:无信用不足场景下的5秒延迟,是因为带过滤的消费者默认使用轮询匹配策略,默认轮询间隔为5秒。可修改Broker端配置缩短间隔:
<address-settings>
    <address-setting match="REPLYQ1">
        <!-- 缩短消费者轮询间隔为100ms -->
        <consumer-poll-period>100</consumer-poll-period>
    </address-setting>
</address-settings>

或在客户端消费时设置consumer.setPollPeriod(100)。

四、额外优化建议

  • 针对大消息(5mb),启用消息压缩:在客户端和Broker端配置compression-enabled=true,减少网络传输和内存占用
  • 调整Broker线程池:增大core-threads和max-threads,提升消息处理能力:
<core thread-pool-max-size="200" core-threads="50"/>
  • 监控Broker指标:通过Artemis控制台或JVM监控,跟踪队列消息数、内存占用、线程状态,定位瓶颈

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 16:22:20