ActiveMQ 持久化的基本介绍
- 持久化就是高可用的机制,即使服务器宕机了,消息也不会丢失的机制。
- 为了避免意外宕机以后丢失信息,需要做到重启后可以恢复消息队列,消息系统一般都会采用持久化机制。
- ActiveMQ的消息持久化机制有AMQ,KahaDB,JDBC和LevelDB,无论使用哪种持久化方式,消息的存储逻辑都是一致的。
- 在发送者将消息发送出去后,消息中心首先将消息存储到本地数据文件、内存数据库或者远程数据库等。再试图将消息发给接收者,成功则将消息从存储中删除,失败则继续尝试尝试发送。
- 消息中心启动以后,要先检查指定的存储位置是否有未成功发送的消息,如果有,则会先把存储位置中的消息发出去。
AMQ(了解)
- 基于文件的存储方式,是以前的默认消息存储,现在不用了
- AMQ是一种文件存储形式,它具有写入速度快和容易恢复的特点。消息存储在一个个文件中,文件的默认大小为32M,当一个文件中的消息已经全部被消费,那么这个文件将被标识为可删除,在下一个清除阶段,这个文件被删除。AMQ适用于ActiveMQ5.3之前的版本
KahaDB (默认)
基于日志文件,从ActiveMQ5.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>
存储说明:
- KahaDB是目前默认的存储方式,可用于任何场景,提高了性能和恢复能力。
- 消息存储使用一个事务日志和仅仅用一个索引文件来存储它所有的地址。
- KahaDB是是一个专门针对消息持久化的解决方案,它对典型的消息使用模式进行了优化。
- 数据被追加到data logs中。当不再需要log文件中的数据的时候,log文件会被丢弃。
存储原理:
四类文件+一把锁 ==》 KahaDB
- db-.log 存储数据,一个存满会再次创建 db-2、db-3 …… ,当不会有引用到数据文件的内容时,文件会被删除或归档
- db.data 是一个BTree 索引,索引了消息数据记录的消息,是消息索引文件,它作为索引指向了 db-.log 里的消息, 类似mysql 数据库,新建一张表,就有这个表对应的 .MYD 文件,作为它的数据文件,就有一个 .MYI 作为索引文件。
- db.free 当前db.data文件里哪些页面是空闲的,文件具体内容是所有空闲页的ID
- db.redo 当 KahaDB 消息存储在强制退出后启动,用于恢复 BTree 索引
- lock 顾名思义就是锁
LevelDB (了解)
-
这种文件系统是从ActiveMQ5.8之后引进的,它和KahaDB非常相似,也是基于文件的本地数据库存储形式,但是它提供比KahaDB更快的持久性。
-
但它不使用自定义B-Tree实现来索引独写日志,而是使用基于LevelDB的索引
-
题外话:为什么LeavelDB 更快,并且5.8 以后就支持,为什么还是默认 KahaDB 引擎,因为 activemq 官网本身没有定论,LeavelDB 之后又出了可复制的LeavelDB 比LeavelDB 更性能更优越,但需要基于 ZooKeeper 所以这些官方还没有定论,仍旧使用 KahaDB。
默认配置如下:
<persistenceAdapter>
<levelDB directory="activemq-data"/>
</persistenceAdapter>
JDBC消息存储
该模式是把消息持久化到数据库中
配置步骤
-
添加mysql数据库的驱动包到activemq 的 lib文件夹
-
修改配置文件activemq.xml中的
<persistenceAdapter>
标签<persistenceAdapter> <jdbcPersistenceAdapter dataSource="#mysql-ds" /> </persistenceAdapter>
dataSource
:指定将要引用的持久化数据库的bean名称,
createTablesOnStartup
:是否在启动时创建数据表,默认值是true,这样每次启动都会去创建数据表了,一般是第一次启动的时候设置
-
在activemq.xml 中 新增标签
dataSource指定将要引用的持久化数据库的bean名称,在 broker 标签和 import标签 之间添加 如下配置:
<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://192.168.72.129:3306/activemq?relaxAutoCommit=true" /> <property name="username" value="root" /> <property name="password" value="123456" /> <property name="maxTotal" value="200" /> <property name="poolPreparedStatements" value="true" /> </bean>
-
数据库建库
建一个名为activemq的数据库
ActiveMQ 启动后会自动在 mysql 的activemq 数据库下创建三张表: activemq_msgs 、activemq_acks、activemq_lockactivemq_acks
:用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存activemq_lock
:在集群环境中才有用,只有一个Broker可以获得消息,称为Master Brokeractivemq_msgs
:用于存储消息,Queue和Topic都存储在这个表中如果新建数据库OK+上述配置OK+代码运行OK,3张表会自动生成。通过data/activemq.log可以查看启动日志。
-
建库,启动遇到的坑
如果建库的时候,使用UTF-8编码会报错,因为创建索引的长度限制,改为GBK就可以解决问题 -
启动acitvemq ,查看建表情况:
-
发送消息(持久化消息)数据会存在 ACTIVEMQ_MSGS 表中
JDBC Message store with ActiveMQ Journal
- 这种方式克服了JDBC Store的不足,JDBC每次消息过来,都需要去写库读库。
- ActiveMQ Journal,使用高速缓存写入技术,大大提高了性能。
- 当消费者的速度能够及时跟上生产者消息的生产速度时,journal文件能够大大减少需要写入到DB中的消息。
举个例子:
生产者生产了1000条消息,这1000条消息会保存到journal文件,如果消费者的消费速度很快的情况下,在journal文件还没有同步到DB之前,消费者已经消费了90%的以上消息,那么这个时候只需要同步剩余的10%的消息到DB。
如果消费者的速度很慢,这个时候journal文件可以使消息以批量方式写到DB。
配置修改:
<persistenceFactory>
<journalPersistenceAdapterFactory
journalLogFiles="5"
journalLogFileSize="32768"
useJournal="true"
useQuickJournal="true"
dataSource="#mysql-ds"
dataDirectory="activemq-data" />
</persistenceFactory>