ActiveMq Kahadb

The KahaDB Message Store Internals

在解决storage useage较高的问题时,详细研究了一下KahaDB Message Store的内部构造。ActiveMq 默认存储消息使用的是AMQ Message Store,KahaDB Message Store是一种新的消息存储库,主要是为了解决ActiveMq Message Store的一些限制,关于AMQ Message Store请参考AMQ Message Store ,AMQ Message Store对每个索引使用两个单独的文件(每个destination有一个索引),并且如果未正确关闭ActiveMQ Broker,恢复速度可能会很慢。原因是需要重建所有索引,从而需要broker遍历所有的消息日志。为了克服这些限制,KahaDB消息存储库为其索引使用了事务日志,而且所有的Destination仅使用一个索引文件。

Kahadb Message Store

这是一个Kahadb Message Store的构造图:

  • The Data Logs: 是一个消息和命令的日志(例如事务边界和消息删除),存储在一个固定大小的文件中。当达到设置的最大文件大小时候,会创建一个新的数据文件。文件中的所有消息都是引用计数的,所以一旦文件中的所有消息不在被需要,也就是引用计数变为0,那么文件就会被删除或者归档

  • The Cache: 在消息被写入日志文件之后,Cache也会保留消息在内存中以便于快速查找,Cache会定期的将消息ID和消息在Data Logs中的位置更新到引用存储索引(Btree Indexes)中,这个过程称为执行检查点(checkpoint)。一旦Btree Indexes更新完成之后,消息就能够安全的从Cache中删除。cache更新Btree Indexes的时间间隔是可以配置的,通过设置checkpoinInterval属性。如果ActiveMQ消息代理达到其内存限制,也会发生检查点(checkpoint)。

  • The BTree Indexes:保存了日志文件中消息的引用,并且根据消息的ID建立了索引。The BTree Indexes维护了队列的FIFO的数据结构和持久订阅者指向其主题消息的指针。redo log仅会使用在ActiveMq broker尚未彻底关闭时,为了确保Btree Indexes的完整性。

The KahaDB Message Store Directory Structure

The KahaDB Message Store目录结构如下图:

Kahadb Message Store Directory Structure
  • db log files Kahadb 会把消息存储到一个预定义大小的名称为db-<Number>.log的数据文件中。当一个数据文件满了,一个新的文件就会被创建, 文件名称中的<Number>会增加,当文件中所有的消息没有任何引用时,文件会被删除或者归档。

  • The archive directory : 只有当archiveDataLogs属性被设置为true的时候,才会有这个文件夹,该文件夹下存储的是不再需要的db log文件,可以用于以后回放消息。

  • db.data: 该文件包含指向数据日志(db log file)中消息的BTree索引。

  • db.redo:当ActiveMq在一次硬件停机之后启动时,用于恢复Btree索引。

从上面可以看出,消息是存储在db-<Number>.log文件中,而db.data文件中保存了消息的引用以及给队列维护了一个FIFO的数据结构,当消息被消费后,db.data 中消息的引用就会出队,此时指向该消息的引用计数就会变化,当db-<Number>.log中所有消息的引用计数都为0时,也就是所有消息都被消费了之后,db-<Number>.log文件才会被删除或者归档。这里有个比较需要注意的点是db-<Number>.log文件默认大小是32M(可以通过journalMaxFileLength属性进行修改),如果这个文件中有一条消息存在对其的引用那么整个文件是不会被清理的,所以如果不定期存在一些消息不能被消费,而这些消息又分别存储到了不同的db-<Number>.log文件中,那么这些db-<Number>.log都不会被清除,这就会导致从ActiveMq web console中看到pending message数量不多,但是storage useage却显示存储占用很多的情况。处理方法一种就是降低db-<Number>.log的大小,并增加kahadb配置的存储空间,还有一种就是定时清理这些pending message,这样db-<Number>.log就能够被及时清理,从而降低存储空间的占用。