启用 stomp 后的 activemq oom

Posted

技术标签:

【中文标题】启用 stomp 后的 activemq oom【英文标题】:activemq oom after enabling stomp 【发布时间】:2016-09-06 16:03:06 【问题描述】:

在 Activemq 服务器上启用 STOMP 协议(​​在仅启用默认协议之前)后,它开始因 oom 而失败。我只有 1 个使用 STOMP 的客户。它可以工作 1 周而不会失败或在重新启动后一天失败。这是配置文件:

<beans
  xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">

    <bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery"
          lazy-init="false" scope="singleton"
          init-method="start" destroy-method="stop">
    </bean>

    <!--
        The <broker> element is used to configure the ActiveMQ broker.
    -->
    <broker useJmx="true" xmlns="http://activemq.apache.org/schema/core" brokerName="cms-mq" dataDirectory="$activemq.data">

        <destinationInterceptors>
            <virtualDestinationInterceptor>
                <virtualDestinations>
                    <virtualTopic name="VirtualTopic.>" selectorAware="true"/>
                </virtualDestinations>
            </virtualDestinationInterceptor>
        </destinationInterceptors>

        <destinationPolicy>
            <policyMap>
              <policyEntries>
                <policyEntry topic=">" producerFlowControl="false">
                </policyEntry>
                <policyEntry queue=">" producerFlowControl="false">
                </policyEntry>
              </policyEntries>
            </policyMap>
        </destinationPolicy>

        <managementContext>
            <managementContext createConnector="false"/>
        </managementContext>
        <persistenceAdapter>
            <kahaDB directory="$activemq.data/kahadb"/>
        </persistenceAdapter>
          <systemUsage>
            <systemUsage>
                <memoryUsage>
                    <memoryUsage percentOfJvmHeap="70" />
                </memoryUsage>
                <storeUsage>
                    <storeUsage limit="4 gb"/>
                </storeUsage>
                <tempUsage>
                    <tempUsage limit="4 gb"/>
                </tempUsage>
            </systemUsage>
        </systemUsage>

        <transportConnectors>
            <transportConnector name="auto" uri="auto+nio://0.0.0.0:61616?maximumConnections=1000&amp;auto.protocols=default,stomp"/>
        </transportConnectors>
        <shutdownHooks>
            <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
        </shutdownHooks>

        <plugins>
          ... security plugins config...
        </plugins>

    </broker>

    <import resource="jetty.xml"/>

</beans>

开始参数:

/usr/java/default/bin/java -Xms256M -Xmx1G -Dorg.apache.activemq.UseDedicatedTaskRunner=false -XX:HeapDumpPath=/var/logs/heapDumps -XX:+HeapDumpOnOutOfMemoryError -Dcom.sun.management.jmxremote.port=8162 -Dcom.sun.management.jmxremote.rmi.port=8162 -Dcom.sun.management.jmxremote.password.file=/opt/apache-activemq-5.13.0//conf/jmx.password -Dcom.sun.management.jmxremote.access.file=/opt/apache-activemq-5.13.0//conf/jmx.access -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote -Djava.awt.headless=true -Djava.io.tmpdir=/opt/apache-activemq-5.13.0//tmp -Dactivemq.classpath=/opt/apache-activemq-5.13.0//conf:/opt/apache-activemq-5.13.0//../lib/ -Dactivemq.home=/opt/activemq -Dactivemq.base=/opt/activemq -Dactivemq.conf=/opt/apache-activemq-5.13.0//conf -Dactivemq.data=/opt/apache-activemq-5.13.0//data -jar /opt/activemq/bin/activemq.jar start

更新: 来自 Eclipse 内存分析器:

Leak Suspects
247,036 instances of "org.apache.activemq.command.ActiveMQBytesMessage", loaded by "java.net.URLClassLoader @ 0xc02e9470" occupy 811,943,360 (76.92%) bytes. 

81 instances of "org.apache.activemq.broker.region.cursors.FilePendingMessageCursor", loaded by "java.net.URLClassLoader @ 0xc02e9470" occupy 146,604,368 (13.89%) bytes.

更新: 在出现 OOM 错误之前,日志中有几个错误,如下所示:

| ERROR | Could not accept connection from null: java.lang.IllegalStateException: Timer already cancelled. | org.apache.activemq.broker.TransportConnector | ActiveMQ BrokerService[cms-mq] Task-13707
| INFO  | The connection to 'null' is taking a long time to shutdown. | org.apache.activemq.broker.TransportConnection | ActiveMQ BrokerService[cms-mq] Task-13738

在调试它时会提供任何帮助。 如果需要,可以提供更多信息。

【问题讨论】:

【参考方案1】:

一种猜测是,您正在通过 STOMP 向代理发送来自生产者的消息,并最终耗尽代理内存。您已经关闭了生产者流控制,即使使用默认的 JMS 客户端也会导致这种情况,并且 STOMP 更容易进入这种情况,因为默认情况下没有返回到生产者的 ack 以允许流控制机制,您必须在每次发送时请求收据才能收到。

要对此进行调试,您需要开始通过控制台或您选择的其他工具检查代理日志以及目标和使用情况统计信息,以查看代理的状态。

【讨论】:

我将打开生产者流控制。看看有没有帮助 只有在您还修改 STOMP 客户端以在发送时请求收据时,才启用生产者流控制。 我设法通过与 stopm 客户端循环连接然后断开连接来重现 OOM。堆大小一直在增长,直到 OOM。它表明了什么? 您应该收集数据并在他们的用户邮件列表中向项目寻求帮助。【参考方案2】:

我检查了客户端代码(ruby stomp 客户端),结果发现存在没有“client-id”连接头的“activemq.subscriptionName”子头。当您设置“activemq.subscriptionName”订阅标头时,这意味着您希望您的订阅者是持久的。但是您还应该设置“client-id”连接标头,否则它会自动生成。如果未设置“client-id”标头,我们会遇到代理在重新连接时无法通过其客户端 ID 识别 stomp 客户端的情况。结果,有很多离线的持久主题订阅者,并且每个 client-id => OOM 错误都会堆积消息。

【讨论】:

以上是关于启用 stomp 后的 activemq oom的主要内容,如果未能解决你的问题,请参考以下文章

ActiveMQ、STOMP、Java 示例

如何将事务与 Stomp 和 ActiveMQ(和 Perl)一起使用?

ActiveMQ + NodeJS + Stomp 极简入门

无法使用 STOMP 向 activemq 发送消息

使用 ruby​​ 和 stomp 将消息写入 ActiveMQ

ActiveMQ:Openwire vs AMQP vs Stomp