ActiveMQ 中的消息持久化(一)

 为了防止系统意外down机丢失消息,同时能在系统恢复后能重新发送原来未发送的消息。一般消息系统都会采用持久化机制。Activemq5.4提供了几种持久化机制: 
1、KahaDB message store 
2、Journaled JDBC adapter 
3、Non-journaled JDBC adapter 

    为了保持后向兼容性,Activemq5.4同样提供以前版本中的持久化机制。例如:AMQ message store以及 Kaha persistence adapter。5.4中默认的采用KahaDB,KahaDB是一种可嵌入式的事务性的持久化机制。要启用或禁用持久化可以通过配置文件中的broker标签中的persistent属性设置 

Xml代码   收藏代码
  1. <broker persistent="false" ...>  
  2.   ...  
  3. </broker>  


true : 启用持久化 
false : 禁用持久化,即便是在配置文件中配置了persistence adapter。 

修改配置文件中的persistenceAdapter或者persistenceFactory可以修改Activemq提供的默认机制。具体可以查看后面的配置文件。 

下面详细介绍KahaDB,主要特性有: 
1、日志形式存储消息。 
2、消息索引以B-Tree结构存储,可以快速更新 
3、完全支持JMS事务 
4、支持多种恢复机制 
下面是KahaDB的一段简短配置: 

Xml代码   收藏代码
  1. <broker brokerName="broker" persistent="true" useShutdownHook="false">  
  2.   ...  
  3.   <persistenceAdapter>  
  4.     <kahaDB directory="activemq-data" journalMaxFileLength="32mb"/>  
  5.   </persistenceAdapter>  
  6. </broker>  


directory : 指定持久化消息的存储目录 
journalMaxFileLength : 指定保存消息的日志文件大小,具体根据你的实际应用配置 



    上图展示的是KahaDB的结构图。消息存储在基于文件的数据日志中。如果消息发送成功,变标记为可删除的。系统会周期性的清除或者归档日志文件。消息文件的位置索引存储在内存中,这样能快速定位到。定期将内存中的消息索引保存到metadata store中,避免大量消息未发送时,消息索引占用过多内存空间。 
Data logs 
数据日志中保存着消息以及目的地、订阅、事务等相关信息。这些信息在日志文件中并未按照一个特定的格式来保存,所以就需要索引各类信息,以便能快速定位到。 
Metadata cache 
在内存中保存日志文件中各类信息的索引,索引信息包含一个MessageId与消息在日志文件中的偏移量的对应关系。所有索引以B-Tree结构存在内存中,便于在一个有序的list上快速的查找,插入以及删除。内存中的消息索引会定期的保存到Metadata store中。具体时间周期可以设置checkpointInterval属性。理想情况下Metadata cache越大愈好,这样在定位消息的时候就不尽量少的去Metadata store中获取索引了。实际可以参考db.data文件的大小来设置。indexCacheSize 便是设置缓存的大小。 
Metadata store 
在db.data文件中保存消息日志中消息的元数据,也是以B-Tree结构存储的,定时从Metadata cache更新数据。同时,Metadata store中也会备份一些在消息日志中存在的信息,这样可以让Broker实例快速启动。即便metadata store文件被破坏或者误删除了。broker可以读取Data logs恢复过来,只是速度会相对较慢些。 
Metadata cache与Metadata store同步 
KahaDB提供了两种触发同步设置 
1、设定一个阀值,当Metadata cache与Metadata store中的索引不同的数量达到这个阀值时,触发同步。indexWriteBatchSize 
便是设置这个阀值。 
2、设置一个时间周期,当时间周期到了后,不管Metadata cache与Metadata store是否不同,都触发同步。 
通过checkpointInterval设置一个时间周期。 

通常为了达到更高的性能,会将indexWriteBatchSize值设置很大。只在到达checkpointInterval时间点时才同步。这样做的风险就是有可能在系统意外down机时丢失部分metadata信息。