Java 如何避免ActiveMQ检查点调用后阻塞队列浏览
当使用ActiveMQ处理大量持久性队列(250)和1000条持久性文本消息(10 KB)时,会出现问题 场景要求这些消息在存储中保留很长一段时间(几天),直到它们被消费(大量数据被暂存以分发给许多消费者,这些消费者可能会离线几天) 在持久性存储充满这些消息之后,在代理重新启动之后,我们可以浏览/使用一些队列,直到30秒后的#checkpoint调用 此调用导致代理使用所有可用内存,并且从不将其释放用于其他任务,例如队列浏览/使用。在内部,MessageCursor似乎决定内存不足,并停止向浏览器/消费者传递队列内容 =>有没有办法通过配置来避免这种行为,或者这是一个bug? 我们的期望是,我们可以在任何情况下使用/浏览任何队列 下面的设置已投入生产一段时间,ActiveMQ文档中提供了一些建议(目标策略、系统使用、持久性存储选项等)Java 如何避免ActiveMQ检查点调用后阻塞队列浏览,java,memory,activemq,leveldb,kahadb,Java,Memory,Activemq,Leveldb,Kahadb,当使用ActiveMQ处理大量持久性队列(250)和1000条持久性文本消息(10 KB)时,会出现问题 场景要求这些消息在存储中保留很长一段时间(几天),直到它们被消费(大量数据被暂存以分发给许多消费者,这些消费者可能会离线几天) 在持久性存储充满这些消息之后,在代理重新启动之后,我们可以浏览/使用一些队列,直到30秒后的#checkpoint调用 此调用导致代理使用所有可用内存,并且从不将其释放用于其他任务,例如队列浏览/使用。在内部,MessageCursor似乎决定内存不足,并停止向浏览
- 使用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)
如果我们在destinationPolicy中将光标或MormoryHighwatermark设置为更高的值,如150或600,这取决于MemorySage和可用堆空间之间的差异,可以稍微缓解这种情况,但在我看来,这并不是生产系统的真正选择
带有Oracle任务控制信息的屏幕,显示从未从内存中释放的ActiveMQTextMessage实例:
我也有类似的问题,ActiveMQ并不是真正设计成“数据库”;消息必须流经ActiveMQ,对于这些长期存储,我建议使用数据库或使用FTP交换文件
我还建议使用producerFlowControl=“true”,这样,如果ActiveMQ无法处理消息,它将减慢生产者的速度。我们可以通过更改(队列)目标来解决问题 保单条目 经过彻底的调查(不更改ActiveMQ源代码),目前的结果是,我们需要接受单个MemoryLit参数定义的限制,该参数用于#检查点/清理过程和浏览/使用队列 1.)内存 如果我们一起使用更高的MemoryLit(内存限制),就不会有问题 具有更高的最大堆),以支持每 #检查点/清理工作流期间的目的地以及我们对 浏览/使用邮件 但在我们的场景中,更多的内存不是一个选项,我们需要处理1024m最大堆和500m内存限制 除此之外,还应详细讨论(IMHO)不断设置更高的MemoryLimit,因为更持久的队列包含数百/数千条挂起的消息以及某些脱机/非活动的使用者场景 2.)持久适配器 我们排除了持久性适配器是问题的原因,因为如果我们切换不同类型的持久性存储(KahaDB、LevelDB、JDBC-PostgreSQL),行为不会改变 在与KahaDB的调试会话期间,我们还看到定期的检查点处理,存储按预期进行管理 3.)目的地策略/到期检查 如果我们禁用缓存和过期检查(这是问题的实际原因),我们的问题就会完全消失 相应的属性都有文档记录,并且有一篇关于消息优先级的不错的博客文章,其中的描述非常适合我们的场景:
<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>
如果我们不再在mem缓存中使用,并且永远不再使用,后果是显而易见的
检查消息是否过期
由于我们既不使用消息过期时间,也不使用消息优先级,而且当前的消息调度速度对我们来说足够快,因此,考虑到给定的系统限制,这种权衡是可以接受的
您还应该考虑在特定工作流期间为内存消耗定义良好的预取限制。在我们的场景中,消息大小可以是2字节,最大可达约100 KB,因此更多的单个策略条目和客户端使用者配置可能有助于优化有关性能和内存使用的系统行为(请参阅)。我尊重您的意见(我们有类似的方法使用dl链接处理大量数据)。但即便如此,根据MSG的数量也会有一个问题,这会导致对内存的强烈依赖性,这仅仅是因为为#checkpoint或#cleanup在队列内容中分页。在处理持久存储之后,必须有更好的垃圾收集。主动生产者流量控制不是一个选项,这实际上会导致我们之间的紧密耦合
<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>