我的任务是调查为什么 db-*.log 文件没有被清除。
从我通过大量搜索发现的情况来看,一切都表明消息仍在队列中。我查看了所有已配置主题的队列中的 hawtio,队列大小为零。
据我了解,理论上 Enqueue 大小和 Dequeue 大小应该相同,但事实并非如此。似乎我的出列大小为 0。
我查看了这些主题,但没有清除它们的操作。
我希望能够清除所有消息,以便 kahadb 日志消失。
我认为您指出了 ActiveMQ 本身的一个弱点:它不能保证消费者在消费消息时非常严格。
我们的 ActiveMQ (5.10.7) 也有类似的问题,因为 KahaDB 看起来像是“磁盘碎片”,我们注意到这可能来自消费者的至少两个问题:
案例一:慢消费者
我们的系统中有一个不能同时消费许多消息的消费者。如果只有一条未使用的消息留在 KahaDB 页面中,它将保留整个页面(以及所有其他已被使用和确认的消息)。为了防止 KahaDB 存储达到 100%(这将减慢生产者的速度),我们将消息传输到另一个 ActiveMQ 实例临时队列中,如下所示:
from("activemqPROD:queue:BIG_QUEUE_UNCONSUMED")
.to("activemqTEMP:queue:TEMP_BIG_QUEUE");
然后将它们推回去:
from("activemqTEMP:queue:TEMP_BIG_QUEUE")
.to("activemqPROD:queue:BIG_QUEUE_UNCONSUMED");
另一种方法是将它们存储在文件系统上,然后重新加载它们,但是您会丢失 JMS(和自定义)标头。使用临时队列解决方案,您可以保留所有标题。
案例2:从不确认的消费者
有时即使我们进行了前面的操作,即使所有未使用的队列都是空的,存储也保持在 0% 以上。通过查看 KahaDB 文件,我们可以看到仍然存在页面,甚至所有 QUEUES 中都没有消息。对于 TOPICS,我们停止使用持久订阅,那么存储也应该保持在 0%。
潜在的原因(这是一个假设,但有很强的信心)是某些消费的消息从未acknowledged
正确处理过。我们之所以认为这是原因,是因为在日志中,我们仍然可以看到消息
"not removing data file: 12345 as contained ack(s) refer to referenced file: [12344, 12345]"
例如,当消费者突然断开连接时(他们消费了一些消息,但在发送之前断开连接ack
)
,可能会发生这种情况。在我们的例子中,消息永不过期,那么这也可能是这种情况下的潜在问题。但是,尚不清楚设置过期是否会破坏“未确认”消息。因为我们不想丢失任何事件,所以这些特定队列没有过期时间。
根据您的问题,看来您属于第二种情况,那么我们的解决方案是:
不幸的是,我们没有找到更好的方法来处理这些案例,如果其他人有更好的选择,我们很乐意知道。
本文还可以为您提供一些解决方案(例如为 ActiveMQ.DLQ 队列设置过期策略)。
将此日志配置添加到 log4j.properties。然后,您可以在 kahadb.log 中准确查看保存 kahadb 文件的内容。
log4j.appender.kahadb=org.apache.log4j.RollingFileAppender
log4j.appender.kahadb.file=${activemq.base}/data/kahadb.log
log4j.appender.kahadb.maxFileSize=1024KB
log4j.appender.kahadb.maxBackupIndex=5
log4j.appender.kahadb.append=true
log4j.appender.kahadb.layout=org.apache.log4j.PatternLayout
log4j.appender.kahadb.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
log4j.logger.org.apache.activemq.store.kahadb.MessageDatabase=TRACE, kahadb
作为替代方案:一旦您发现哪个队列导致日志存在,您可以将其映射到它自己的 KahaDB,如此处所述http://activemq.apache.org/kahadb.html