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

How to avoid blocking of queue browsing after ActiveMQ checkpoint call

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

一个场景要求这些消息在存储中保留很长时间(几天),直到它们被消费(大量数据被暂存以分发给许多消费者,这可能会离线几天)。

在 Persistence Store 充满这些消息后,在代理重新启动后,我们可以 browse/consume 一些队列 直到 30 秒后 #checkpoint 调用。

此调用会导致代理使用所有可用内存,并且永远不会将其释放用于队列 browse/consume 等其他任务。在内部,MessageCursor 似乎决定没有足够的内存并停止将队列内容传送到 browsers/consumers。

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

期望我们可以在任何情况下consume/browse任何队列。

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

除了上述设置外,我们还为代理使用以下设置(顺便说一句:将 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>

如果我们将 destinationPolicy 中的 cursorMemoryHighWaterMark 设置为更高的值,例如 150600 根据 memoryUsage 和可用堆之间的差异 space 可以稍微缓解这种情况,但在我看来,这并不是生产系统的真正选择。

带有来自 Oracle Mission Control 的信息的屏幕显示那些永远不会从内存中释放的 ActiveMQTextMessage 实例:

http://goo.gl/EjEixV

我遇到了类似的问题,ActiveMQ 并不是真正设计成 "database";消息必须流经 ActiveMQ,对于这些 long-term 存储,我建议使用数据库或使用 FTP.

交换文件

我还建议使用 producerFlowControl="true" 这样如果 ActiveMQ 无法处理消息,它会降低生产者的速度。

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

经过彻底调查(w/o 更改 ActiveMQ 源代码),结果是现在我们需要接受由用于 #checkpoint/cleanup 进程和browsing/consuming 个队列。

1.) 内存

没有问题,如果我们使用更高的内存限制(一起 具有更高的 max-heap) 以支持每个消息缓存 #checkpoint/cleanup 工作流程中的目的地以及我们的要求 browse/consume 封邮件。

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

除此之外,不断设置更高的 memoryLimits 只是因为更多持久队列包含 hundreds/thousands 待处理消息以及某些 offline/inactive 消费者场景应该详细讨论(恕我直言)。

2.) 永久适配器

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

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

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

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

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

我们只是将 useCache="false" 和 expireMessagesPeriod="0" 添加到 政策条目:

<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>

后果很明显,如果我们不再使用 in-mem 缓存并且永远不会 检查消息是否过期。

因为我们既不使用消息过期也不使用消息优先级,而且当前的消息调度对我们来说已经足够快了,考虑到给定的系统限制,这个 trade-off 是可以接受的。

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