You need to enable JavaScript to run this app. ActiveMQ Artemis 2.17主从HA下“投递中”消息卡住不释放问题问询
优惠活动
大模型
产品
解决方案
定价
更多

ActiveMQ Artemis 2.17主从HA下“投递中”消息卡住不释放问题问询

问题梳理

你在2.17版本ActiveMQ Artemis双节点主从(共享文件系统HA)架构下遇到的投递消息永久滞留问题,核心复现特征如下:

  • 强制关停主节点后从节点可正常接管服务,消费端能收到后续新流入的消息
  • 队列中部分消息永久卡在in delivery状态,即使存在在线消费者、新消息流转正常,这类消息也不会被重投
  • 已尝试配置Broker端<connection-ttl-override>、客户端连接串设置connectionTtl、切换CachingConnectionFactory/JmsPoolConnectionFactory两种连接池实现,均无法触发残留连接清理、释放滞留消息
  • 仅能通过重启消费者应用解锁滞留消息,无法满足生产环境可用性要求
根因定位

你最初判断的“残留连接绑定投递状态导致消息无法回收”的方向是正确的,之前配置不生效核心是踩了两个版本和配置层面的坑:

  1. 2.17版本HA场景的持久化状态清理缺陷
    主节点被强制关停时,未完成事务确认的投递状态会被持久化到共享存储;从节点接管加载队列元数据时,会直接把这部分消息标记为in delivery状态,绑定到原来的会话ID上。但这些会话对应的TCP连接已经随主节点关停消失,从节点根本没有对应的连接上下文,常规的connection-ttl/connection-ttl-override配置因为找不到对应的连接对象,完全不会触发超时清理逻辑,消息就永久卡在当前状态。
  2. 客户端连接缓存的失效残留
    你使用的CachingConnectionFactory默认会缓存Session、Consumer实例,当主从切换底层TCP连接断开重连后,缓存里的旧Session句柄没有被正确校验有效性,导致Broker侧给旧Session标记的投递消息,永远等不到对应的事务提交确认信号,进一步加重滞留问题。你之前仅设置cacheConsumers=false没有解决问题,是因为Session缓存依然存在,对transacted模式的消费者来说,失效的Session会直接导致投递消息无响应。
无需重启消费者的自动释放方案

方案1:Broker队列层配置投递超时(最适配场景,优先推荐)

这个是Artemis原生提供的能力,直接在队列层面监听消息的投递时长,不依赖TCP连接上下文,完全绕开之前TTL配置不生效的问题。
在broker.xml中针对业务队列增加投递超时配置,超时后自动将in delivery状态的消息重置、重新入队参与正常投递:

<address name="myQueue">
   <anycast>
      <queue name="myQueue">
         <!-- 投递中消息的超时时间,单位毫秒,建议设置为业务最大处理时长的1.5倍 -->
         <default-delivery-timeout>30000</default-delivery-timeout>
         <!-- 超时时间的动态调整系数,默认1.0即可 -->
         <delivery-timeout-scaler>1.0</delivery-timeout-scaler>
      </queue>
   </anycast>
</address>

配置生效后,哪怕是HA切换产生的僵尸会话绑定的滞留消息,只要超过30秒未被确认,Broker就会自动回收消息状态,不需要等待连接失效判定,完全实现自动解锁,无人工干预要求。

方案2:修正客户端连接配置,从源头减少僵尸会话产生

针对你基于Spring JMS的消费端场景,调整连接工厂配置,消除缓存导致的会话失效问题:

  • 替换全量缓存的CachingConnectionFactory,使用Artemis生态适配的JmsPoolConnectionFactory,对事务型消费者关闭Session和Consumer缓存:
<bean id="pooledConnectionFactory" class="org.messaginghub.pooled.jms.JmsPoolConnectionFactory">
    <property name="connectionFactory">
        <bean class="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory">
            <property name="brokerURL" value="${spring.artemis.brokerUrl}" />
            <property name="user" value="${spring.artemis.user}" />
            <property name="password" value="${spring.artemis.password}" />
            <!-- 客户端每10秒检测一次连接有效性,每30秒无流量的连接主动判定失效 -->
            <property name="clientFailureCheckPeriod" value="10000" />
            <property name="connectionTTL" value="30000" />
        </bean>
    </property>
    <!-- 事务型消费者关闭缓存,避免重连后使用失效的旧Session句柄 -->
    <property name="cacheSession" value="false" />
    <property name="cacheConsumers" value="false" />
    <property name="maxConnections" value="10" />
</bean>
  • 适配现有的int-jms:message-driven-channel-adapter配置,保持acknowledge="transacted"的事务模式不变,即可自动适配新的连接工厂,HA切换后不会残留无效的Session引用。

方案3:运维侧兜底自动化巡检

如果暂不准备调整现有Broker和客户端配置,可以通过Artemis原生的JMX管理接口做定时兜底:

  • 每30秒巡检一次目标队列的消息状态,筛选出投递时长超过业务阈值、状态为in delivery的滞留消息,调用队列的消息恢复接口,强制重置消息状态并重新入队
  • 该逻辑可以集成到现有运维监控平台,不需要改动业务代码,完全自动运行,作为方案1的补充兜底。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 22:15:04