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

ActiveMQ Artemis队列消费异常咨询:读取消息后其余消息消失

问题描述

我需要从ActiveMQ Artemis队列中取出最后一条消息。当前队列存在大量消息,读取一条消息后,其余消息在控制台视觉上消失,但Broker控制台的消息计数器仅显示减少1条。我希望刷新页面时计数器能正常显示减少1条(目前仅断开消费者会话后该功能才生效)。

初始控制台状态

队列包含大量消息,控制台计数显示正常。

读取消息后的现象

读取单条消息后,控制台显示队列已无消息,但消息计数器仅减少1条;只有断开消费者会话后刷新页面,计数器才会正确显示剩余消息数量。

当前消息读取代码

private void getMessage() throws JMSException, NamingException {
    Queue queue = (Queue) initialContext.lookup("dynamicQueues/" + "TestQueue");
    if (messageConsumer == null){
        messageConsumer = queueSession.createConsumer(queue);
    }
    TextMessage message = (TextMessage) messageConsumer.receive();
    String msgBody = ((TextMessage) message).getText();
    System.out.println(msgBody);
}
问题根源

出现该现象是因为ActiveMQ Artemis默认的消息预取机制:创建消费者时,Broker会一次性将大量消息(队列默认预取1000条)推送到消费者本地会话缓存中。此时Broker端的消息计数统计的是未被预取的消息,视觉上"消失"的消息实际是被预取到了消费者本地缓存;只有断开会话时,未被消费的预取消息才会回滚到Broker,计数器才会显示正确的剩余数量。

解决方案

1. 禁用/限制预取数量

设置消费者预取数为1,让Broker仅推送当前需要处理的1条消息,避免大量预取导致计数异常:

private void getMessage() throws JMSException, NamingException {
    Queue queue = (Queue) initialContext.lookup("dynamicQueues/" + "TestQueue");
    // 转换为Artemis专属队列类型,设置预取数
    ActiveMQDestination activeMQQueue = (ActiveMQDestination) queue;
    activeMQQueue.setPrefetchSize(1);
    
    if (messageConsumer == null){
        messageConsumer = queueSession.createConsumer(activeMQQueue);
    }
    
    TextMessage message = (TextMessage) messageConsumer.receive();
    if (message != null) {
        String msgBody = message.getText();
        System.out.println(msgBody);
    }
}

也可以在连接工厂配置中全局设置预取策略:prefetchPolicy.queuePrefetch=1。

2. 消费后关闭消费者/会话

每次消费完成后关闭消费者,让未被消费的预取消息回滚到Broker,保证计数器实时更新:

private void getMessage() throws JMSException, NamingException {
    Queue queue = (Queue) initialContext.lookup("dynamicQueues/" + "TestQueue");
    // 使用try-with-resources自动关闭消费者
    try (MessageConsumer consumer = queueSession.createConsumer(queue)) {
        TextMessage message = (TextMessage) consumer.receive();
        if (message != null) {
            String msgBody = message.getText();
            System.out.println(msgBody);
        }
    }
}

3. 精准获取队列最后一条消息

如果目标是取出队列的最后一条消息(而非第一条),可以通过消息浏览器遍历找到最后一条,再通过消息ID精准消费:

private void getLastMessage() throws JMSException, NamingException {
    Queue queue = (Queue) initialContext.lookup("dynamicQueues/" + "TestQueue");
    // 创建消息浏览器遍历队列
    QueueBrowser browser = queueSession.createBrowser(queue);
    Enumeration<?> messages = browser.getEnumeration();
    TextMessage lastMessage = null;
    
    while (messages.hasMoreElements()) {
        lastMessage = (TextMessage) messages.nextElement();
    }
    browser.close();
    
    if (lastMessage != null) {
        // 通过消息ID筛选,仅消费最后一条消息
        String selector = "JMSMessageID = '" + lastMessage.getJMSMessageID() + "'";
        try (MessageConsumer consumer = queueSession.createConsumer(queue, selector)) {
            TextMessage targetMsg = (TextMessage) consumer.receive(1000);
            if (targetMsg != null) {
                System.out.println(targetMsg.getText());
                targetMsg.acknowledge();
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 14:32:44