ActiveMQ 浏览器需要很长时间才能上次 .hasMoreElements()

ActiveMQ browser needs long time for last .hasMoreElements()

我尝试为 ActiveMQ 实现一个队列浏览器。
下面显示的代码应显示名为 'Q1' 的队列中的文本消息。里面有两条消息。通常它可以工作,但最后一个 e.hasMoreElements() 调用最多需要 20 秒。我想每 500 毫秒更新一次列表。
为什么这么慢?

当我在浏览器视图中按 'update' 立即显示 http://localhost:8161/admin/browse.jsp?JMSDestination=Q1 e.hasMoreElements() returns .这里发生了什么?如何实现'realtime'视图?

        //init:
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
        Connection connection = connectionFactory.createConnection();
        connection.start();
        Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
        Queue queue = session.createQueue("Q1");

        boolean run = true;
        while (run) {
            LOG.info("--------------------------------------------------------------------------------");
            QueueBrowser browser = session.createBrowser(queue);
            Enumeration e = browser.getEnumeration();
            while (e.hasMoreElements()) { //<- very slow before returning false after last message. why?
                Object o = e.nextElement();
                if (o instanceof ActiveMQTextMessage) {
                    LOG.info(((ActiveMQTextMessage) o).getText());
                } else {
                    LOG.info(o.toString());
                }
            }
            Thread.sleep(500);
            browser.close();
        }

        session.close();
        connection.close();

经过一些研究和尝试后,我转向了更新的 JMX 技术。穿过队列时没有性能问题。

一些代码:

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
JMXConnector connector = JMXConnectorFactory.connect(url, null);
connector.connect();
connection = connector.getMBeanServerConnection();
ObjectName name = new ObjectName(getObjectNameByBrokerName(brokerName));
brokerMBean = (BrokerViewMBean) MBeanServerInvocationHandler.newProxyInstance(connection, name, BrokerViewMBean.class, true);

ObjectName[] objNames = brokerMBean.getQueues();
for (ObjectName objName : objNames) {
    QueueViewMBean queueMBean = (QueueViewMBean) MBeanServerInvocationHandler.newProxyInstance(connection, objName, QueueViewMBean.class, true);
    System.out.println(queueMBean.getName());
}

您必须在配置中激活 jmx。默认情况下它是停用的。

根据我之前的评论,我发现在连接工厂上调用 setTransactedIndividualAck(true) 可以解决问题

ActiveMQConnectionFactory cf2 = new ActiveMQConnectionFactory(...);
cf2.setTransactedIndividualAck(true); 

我不确定这是解决问题的正确方法,但至少它现在有效。在此处查看 ActiveMQ 用户论坛上的消息: http://activemq.2283324.n4.nabble.com/JMS-browser-getEnumeration-hasMoreElements-takes-15s-on-last-element-td4709969.html

我遇到了同样的问题。但是更改会话确认消除了延迟。

试试这个:

Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

我发现在我的 hasMoreElements() 循环中调用 Session.commit() 停止使用 activemq-broker 版本 5.14.5:

的挂起
while(enumeration.hasMoreElements()) {
    final Message     message     = (Message)enumeration.nextElement();
    final TextMessage textMessage = (TextMessage)message;
    session.commit();
}

我做了更多研究,看看这是否是 ActiveMQ 的错误,发现 activemq-broker 版本 5.15.1 没有挂起,即使在每次迭代后都没有调用 commit()。代理的所有先前版本在对 hasMoreElements() 的最终调用时挂起。似乎贡献者并没有故意解决这个特定问题,因为 bug report on JIRA that the change referenced was for something different. The change that fixed this issue 更改了 org.apache.activemq.broker.region.Queue class 的 iterate() 方法的一部分来自:

// are we done browsing? no new messages paged
if (!added || browser.atMax()) {
    browser.decrementQueueRef();
    browserDispatches.remove(browserDispatch);
}

// are we done browsing? no new messages paged
if (!added || browser.atMax()) {
    browser.decrementQueueRef();
    browserDispatches.remove(browserDispatch);
} else {
    wakeup();
}

为了确认这是解决问题的更改,我转到以前的版本 5.15.0 并强制使用调试器调用 wakeup() 并调用 hasMoreElements()没挂。