如何避免在ActiveMQ检查点调用后阻塞队列浏览

jfo*_*rge 6 java memory activemq-classic leveldb kahadb

当将ActiveMQ与大量持久性队列(250)á1000持久性TextMessagesá10 KB一起使用时,会出现问题。

一个场景需要这些消息在很长一段时间(几天)内保留在存储中,直到被消耗为止(为许多消费者分阶段分发大量数据以进行分发,这些数据可能会离线几天)。

在持久性存储中填充了这些消息之后,并且在代理重新启动之后,我们可以浏览/使用一些队列, 直到 30秒后调用#checkpoint。

此调用导致代理使用所有可用内存,而不会将其释放用于其他任务,例如队列浏览/使用。在内部,MessageCursor似乎决定内存不足,并停止将队列内容传送到浏览器/消费者。

=>有没有办法通过配置来避免这种行为,或者这是一个错误?

期望我们可以在任何情况下使用/浏览任何队列。

下面的设置已经投入生产了一段时间,并在ActiveMQ文档中应用了一些建议(目标策略,systemUsage,持久性存储选项等)。

  • 使用ActiveMQ测试行为:5.11.2、5.13.0和5.5.1。
  • 内存设置:Xmx = 1024m
  • Java:1.8或1.7
  • 操作系统:Windows,MacOS,Linux
  • PersistenceAdapter:KahaDB或LevelDB
  • 光盘:足够的可用空间(200 GB)和物理内存(最大16 GB)。

除了上述设置之外,我们还对代理使用以下设置(顺便说一句:将memoryLimit更改为一个较小的值(如1mb)不会改变这种情况):

<destinationPolicy>
    <policyMap>
        <policyEntries>
            <policyEntry queue=">" producerFlowControl="false" optimizedDispatch="true" memoryLimit="128mb" timeBeforeDispatchStarts="1000">
                <dispatchPolicy>
                    <strictOrderDispatchPolicy />
                </dispatchPolicy>
                <pendingQueuePolicy>
                    <storeCursor />
                </pendingQueuePolicy>
            </policyEntry>
        </policyEntries>
    </policyMap>
</destinationPolicy>
<systemUsage>
    <systemUsage sendFailIfNoSpace="true">
        <memoryUsage>
            <memoryUsage limit="500 mb" />
        </memoryUsage>
        <storeUsage>
            <storeUsage limit="80000 mb" />
        </storeUsage>
        <tempUsage>
            <tempUsage limit="1000 mb" />
        </tempUsage>
    </systemUsage>
</systemUsage>
Run Code Online (Sandbox Code Playgroud)

如果我们根据memoryUsage和可用堆空间之间的差异将destinationPolicy中的cursorMemoryHighWaterMark设置为较高的值(例如150600),则可以缓解这种情况,但这对生产系统而言并不是真正的选择。视图。

带有来自Oracle Mission Control的信息的Screenie,显示了从未从内存释放的ActiveMQTextMessage实例:

http://goo.gl/EjEixV

jfo*_*rge 2

我们通过更改(队列)目标策略条目来解决我们的问题。

经过彻底调查(不更改 ActiveMQ 源代码)后,结果是现在我们需要接受由用于#checkpoint/cleanup 过程和浏览/消费队列的单个 memoryLimit 参数定义的限制。

1.) 内存

如果我们使用更高的内存限制(以及更高的最大堆)来支持 #checkpoint/cleanup 工作流程期间每个目标的消息缓存以及我们浏览/使用消息的要求,那么就没有问题。

但在我们的场景中,更多的内存不是一个选择,我们需要处理 1024m max-heap 和 500m memoryLimit。

除此之外,应该详细讨论不断设置更高的内存限制,因为更多的持久队列包含数百/数千条待处理消息以及某些离线/不活动的消费者场景(恕我直言)。

2.) 持久适配器

我们排除了持久适配器作为问题原因的可能性,因为如果我们切换不同类型的持久存储(KahaDB、LevelDB、JDBC-PostgreSQL),行为不会改变。

在 KahaDB 的调试会话期间,我们还看到定期检查点处理,存储按预期进行管理。

3.) 目的地政策/过期检查

如果我们禁用缓存和过期检查(这是问题的实际原因),我们的问题就会完全消失。

相应的属性已记录在案,并且有一篇关于消息优先级的精彩博客文章,其中的描述非常适合我们的场景:

我们只需将 useCache="false" 和 expireMessagesPeriod="0" 添加到policyEntry:

<destinationPolicy>
    <policyMap>
        <policyEntries>
            <policyEntry queue=">" producerFlowControl="false" optimizedDispatch="true" memoryLimit="128mb" timeBeforeDispatchStarts="1000"
                                   useCache="false" expireMessagesPeriod="0">
                <dispatchPolicy>
                    <strictOrderDispatchPolicy />
                </dispatchPolicy>
                <pendingQueuePolicy>
                    <storeCursor />
                </pendingQueuePolicy>
            </policyEntry>
        </policyEntries>
    </policyMap>
</destinationPolicy>
Run Code Online (Sandbox Code Playgroud)

如果我们不再使用内存中缓存并且从不检查消息过期,后果是显而易见的。

由于我们既不使用消息过期也不使用消息优先级,并且当前的消息调度对我们来说足够快,因此对于给定的系统限制,这种权衡是可以接受的。

人们还应该考虑在特定工作流程中明确定义的内存消耗预取限制。在我们的场景中,消息大小可以是 2 字节到大约 2 个字节。100 KB,因此更多单独的策略条目和客户端使用者配置可能有助于优化有关性能和内存使用的系统行为(请参阅http://activemq.apache.org/per-destination-policies.html)。