ActiveMQ Artemis高负载下消息延迟及流控相关问题求助
问题描述
我们基于ActiveMQ Artemis 2.27.1(单节点集群,使用Core协议)搭建了应用套件,流程如下:
- 应用A向REQUEST Q发送消息后,在对应REPLY Q上等待匹配关联ID的响应消息
- 应用B监听并消费REQUEST Q的消息,处理完成后立即向REPLY Q发送匹配关联ID的响应消息,由应用A接收
低负载下运行正常,但**峰值负载(消息大小1k至5mb)**时出现以下问题:
- 应用A发送消息延迟严重(客户端发送到Artemis接收延迟超10秒)
- 应用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秒才完成消费者匹配并投递。
现需明确:
- 流控机制触发的根本原因
- 流控的禁用/优化方法
- 整体延迟问题的解决方案
解决方案分析
一、流控触发原因
- 消费者信用耗尽:应用A在REPLY Q上的消费者使用了基于
JMSCorrelationID的过滤条件,Artemis会为每个带过滤的消费者维护独立的信用额度。当大消息(如5mb)占满信用窗口后,后续消息无法投递,触发“lack of credits”日志。 - 地址阻塞连锁反应:REPLY Q的消费者信用耗尽后,队列消息堆积,达到地址的阻塞阈值(默认是内存/磁盘占满触发),导致应用B向REPLY Q发送消息时被阻塞,进一步加剧整体延迟。
- 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>
三、延迟问题根因与解决
- 发送延迟:应用B发送到REPLY Q被阻塞,导致应用A的请求消息在REQUEST Q堆积,Artemis处理路由延迟。解决上述流控和阻塞问题后,发送延迟会缓解。
- 消费匹配延迟:无信用不足场景下的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
相关产品推荐
相关产品推荐

