迁移至ActiveMQ Artemis后OpenWire JMS客户端停止消费消息
问题
将ActiveMQ "Classic"替换为Artemis Broker 2.28.0后,非Spring Boot的Spring Web应用出现异常:启动后不久停止消费消息,后续连生产也停滞;重启应用仅能消费少量消息后再次卡住。Artemis控制台显示消费者已连接,但无消费行为,应用与Broker日志均无错误或警告。
应用依赖版本:Spring 5.3.20、Spring Integration 5.4.13、Apache ActiveMQ 5.15.9,使用Spring Integration编排异步任务,ConnectionFactory配置如下:
<!-- JMS ConnectionFactory --> <bean id="jmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop"> <property name="connectionFactory"> <bean class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="${jmsBrokerUrl}" /> <!-- <property name="trustAllPackages" value="true"/> --> <property name="trustedPackages"> <list> <value>java.lang</value> <value>java.util</value> <value>java.sql</value> <value>our.custom.domain</value> <value>org.hibernate</value> <value>org.springframework</value> <value>java.io</value> <value>java.net</value> </list> </property> </bean> </property> <property name="maxConnections" value="5" /> <property name="idleTimeout" value="0" /> </bean>
已尝试的排查步骤:
- 检查日志:应用与Broker日志无错误或警告;
- 调整预取策略:设置
jms.prefetchPolicy.all=1,无效果; - 对比Broker配置:发现ActiveMQ "Classic"有特定
policyEntry配置,Artemis的broker.xml中缺失:
<!-- publicrelay needs this --> <policyEntry queue=">" producerFlowControl="true"> <pendingQueuePolicy> <vmQueueCursor/> </pendingQueuePolicy> </policyEntry>
- 检查内存使用:调整堆大小无效,问题与内存无关;
- 查看队列状态:消费停顿时
artemis queue stat显示部分队列存在DELIVERING_COUNT的消息; - 分析线程dump:Broker和应用线程dump显示生产者线程在发送消息时停滞,无其他阻塞线程。
求更多可执行的排查方法。
排查建议
- 替换ActiveMQ客户端为Artemis原生客户端:当前用的是ActiveMQ 5.x的连接工厂和池化实现,虽然Artemis兼容旧客户端,但原生客户端适配性更好。改用
org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory和对应的池化连接工厂,重新配置连接参数后测试。 - 排查消息确认逻辑:队列存在
DELIVERING_COUNT消息,说明消息已投递但未被确认。检查Spring Integration的JMS消费者确认模式配置,确认业务代码中是否存在未手动确认消息、确认逻辑阻塞的情况,比如CLIENT_ACKNOWLEDGE模式下未调用acknowledge()。 - 深挖生产者阻塞细节:线程dump显示生产者停滞,进一步定位阻塞点:
- 检查生产者是否使用事务,若事务未提交/回滚会占用资源导致阻塞;
- 验证Artemis的生产者流控是否触发,可临时关闭流控测试,或查看Broker内存、磁盘阈值是否触发限制;
- 检查Spring Integration线程池状态:应用依赖Spring Integration做异步编排,可能是任务线程池耗尽导致停滞。查看
TaskExecutor的核心线程数、最大线程数、队列容量配置,检查是否有线程被长时间占用未释放。 - 搭建最小化测试场景:剥离复杂业务逻辑,只保留核心JMS生产/消费代码,验证是否能正常运行。如果简化场景正常,再逐步添加原有组件,定位到具体的阻塞环节。
- 开启Artemis DEBUG日志:虽然当前日志无报错,但DEBUG级别能显示消息处理的细节,比如序列化失败、路由异常等隐性问题。同时检查死信队列是否有堆积,确认是否有消息因处理失败被静默转移。
- 验证连接池配置:当前
idleTimeout=0(连接永不超时),maxConnections=5,可能存在连接泄漏或复用异常。开启连接池DEBUG日志,监控连接的创建、使用、销毁流程;尝试调整maxConnections数量,或改用Artemis原生池化连接工厂测试。 - 对齐Artemis与Classic的游标策略:Artemis的游标逻辑和Classic不同,尝试在Artemis的
broker.xml中配置类似vmQueueCursor的策略(Artemis对应vm或file-memory游标),调整队列的持久化和游标配置后测试。
内容的提问来源于stack exchange,提问作者ROMAN
相关产品推荐
相关产品推荐

