本文总结ActiveMQ持久化配置。
官方文档:http://activemq.apache.org/persistence
一.持久化机制简介
为了避免消息队列服务意外宕机后丢失消息,需要做到重启后可以恢复消息队列,消息系统一般都会采用持久化机制。
生产者的消息到达消息队列后,首先存储到本地文件、内存数据库、或者远程数据库,然后在将消息发送给消费者。发送成功,则将消息删除,否则尝试重新发送。消息中心启动后,首先检查对应的存储位置,如果发现未发送成功的消息,则需要把消息发送出去。
ActiveMQ的持久化机制有:JDBC,AMQ,KahaDB,LevelDB,无论哪种机制,消息的存储逻辑都是一致的。
- AMQ :一种文件存储形式,数据写入速度快,容易恢复。消息存储在文件种,默认存储大小为32M,当文件种的消息全部被消费后,标记为可清除状态,下个清除阶段文件被清除。AMQ适用于ActiveMQ5.3及之前的版本。
- KahaDB :5.4及之后版本,默认的持久化插件,使用日志文件。
本文只总结常用的持久化方式
二.KahaDB
ActiveMQ 5.4及之后版本,默认使用此种持久化机制,适用于任何场景,提高了性能和恢复能力。
打开配置文件activemq.xml,会发现如下配置内容:
<!--
Configure message persistence for the broker. The default persistence
mechanism is the KahaDB store (identified by the kahaDB tag).
For more information, see:
http://activemq.apache.org/persistence.html
-->
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
默认配置路径是ActiveMQ安装路径的data目录下:
打开kahadb目录,内容如下:
- db-1.log :存储消息数据,大小可以预定义,比如32M一个,超过32M之后,会产生新的文件db-2.log db-3.log等。当不再有引用到此文件中的任何消息时,文件就会被删除或者归档。
- db.data :存储索引,包含了持久化的BTree索引,本质上是B-Tree,索引了db.log中的记录。
- db.free :(MQ存储数据后会出现此文件)当前db.data中哪些页面是空闲的;此文件保存了空闲页面的ID。
- db.redo :用来进行消息恢复,如果KahaDB在强制退出后启动,此文件可用于恢复BTree索引。
- lock:文件锁,表示当前获得KahaDB读写权限的broker;写独占,查询共享。
三. JDBC
第二节讲述的KahaDB持久化机制,是ActiveMQ本身自带的存储机制,使用本地文件。而JDBC则需要MQ和第三方存储进行配合使用,比如使用Mysql数据库。
上图中的持久化方案部分,就是mysql。本节介绍ActiveMQ如何配合Mysql实现消息持久化。
1.Mysql驱动包
ActiveMQ想要连接Mysql,需要依赖Mysql的连接驱动包,下载mysql-connector-java-版本号.jar,然后将此jar包放置ActiveMQ安装目录的lib目录中。
2.修改持久化方式
将activemq.xml中的persistenceAdapter修改为如下内容:
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="true" />
</persistenceAdapter>
其中,
- mysql-ds 是mysql数据源的配置,也是在activemq.xml中配置;
- createTablesOnStartup=“true” :这个可以不用显示配置,默认就是true,表示在MQ启动的时候,自动创建持久化数据用的数据库表。一般在第一次启动时设置为true,之后再改为false。
3.dataSource="#my-ds"
<bean id="mysql-ds" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://数据库服务IP/activemq?relaxAutoCommit=true"/>
<property name="username" value="自己数据库用户名"/>
<property name="password" value="自己数据库密码"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
</beans>
上述配置,指定了数据库连接池,用户名和密码等连接信息。这里默认时dbcp2的数据库连接池,可以手动改为别的,但是需要在lib中添加对应的依赖包。
4.创建数据库和表
上述配置中,创建了一个名字为activemq的数据库,这个数据库需要提前在mysql中手动创建。
然后在MQ重启后,会自动在此数据库中产生3张数据库表:
- activemq_msgs : 用于存储消息数据;
- activemq_acks : 用于存储订阅关系;
- activemq_lock : 在集群环境中才有用,用于记录哪个broker是当前的 master broker。
5.持久化验证
运行上篇文章《ActiveMQ系列(四)ActiveMQ核心功能总结》中的demo(queue模式),会产生3条点对点的数据,msgs表产生数据如下,
然后,运行消费者的代码,消费消息后,数据库表中数据将会被删除。
另外,对于topic发布订阅模式,
msgs表中的数据,即使被消费也不会删除,这样可以做到查阅历史发布的数据;同时在订阅表acks中会产生订阅者的数据:
四.JDBC Persistence with ActiveMQ Journal
第三节中的JDBC持久化机制,存在一个问题,就是存储比较慢,每次来消息,都要存Mysql,速度受Mysql的限制。
ActiveMQ Journal在ActiveMQ 4.x中引入,使用了高速缓存写入技术,可以大大提高存储性能。当消费者的消费速度接近于生产者的速度时,使用Journal作为缓存,能够大大减少需要要写入DB的消息数量。
当消费者的速度比较慢时,Journal缓存可以定时批量的将数据写入Mysql中。
Journal高速缓存,挡在MQ和Mysql中间,消息先存在缓存,定期刷新到DB中。
配置方式,activemq.xm中:
<persistenceFactory>
<journalPersistenceAdapterFactory
journalLogFiles="4"
journalLogFileSize="32768"
useJournal="true"
useQuickJournal="true"
dataSource="#mysql-ds"
dataDirectory="activemq-data />
</persistenceFactory>
五. LevelDB
ActiveMQ 5.8及以后引入,是一种文件存储,和KahaDB非常相似,也是基于文件的本地数据库存储形式。但是它比kahaDB更快。使用基于LevelDB的索引,不是BTree索引。
此存储机制属于比较新的技术,目前还没有大规模使用,当前推荐使用KahaDB。
启用方式如下:
<broker brokerName="broker" ... >
...
<persistenceAdapter>
<levelDB directory="activemq-data"/>
</persistenceAdapter>
...
</broker>