消息持久化存储
消息持久化,对于可靠消息传递来说是一种比较好的方法,即使发送者和接收者不是同时在线或者消息中心在发送者发送消息后宕机了,在消息中心重启后仍然可以将消息发送出去。消息持久性的原理很简单,就是在发送消息出去后,消息中心首先将消息存储在本地文件、内存或者远程数据库,然后把消息发送给接收者,发送成功后再把消息从存储中删除,失败则继续尝试。
接下来我们来了解一下,消息在broker上的持久化存储实现方式:
ActiveMQ消息持久化存储支持类型
ActiveMQ支持5种不同的持久化方式,主要有如下几种,不过无论使用哪种持久化方式,消息的存储逻辑都是一致的。
如需修改使用其他类型存储,则需要编辑 conf/activemq.xml 文件。
- KahaDB存储(默认存储方式)
- JDBC存储
- Memory存储
- LevelDB存储
- JDBC With ActiveMQ Journal存储
1.KahaDB存储
KahaDB是目前默认的存储方式,可用于任何场景。使用KahaDB存储,提高了性能和数据恢复能力,消息存储使用【一个事务日志】和【仅仅用一个索引文件】来存储它所有的地址。
KahaDB存储是一个专门针对消息持久化的解决方案,它对典型的消息使用模式进行了优化。在Kaha中,数据被追加到data logs日志文件中。当不在需要log日志文件中的数据的时候,可以直接将log文件丢弃。
1.1 KahaDB的配置方式
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
1.2 KahaDB的存储原理
在data/kahadb这个目录下,会生成四个文件:
- db.data 它是消息的索引文件,本质上是B-Tree(B树),使用B-Tree作为索引指向db-*.log里面存储的消息
- db.redo 用来进行消息恢复
- db-*.log 存储消息内容。新的数据以APPEND的方式追加到日志文件末尾。属于顺序写入,因此消息存储是比较快的。默认是32M,达到阀值会自动递增。即:db-1.log、db- 2.log 等递增
- lock文件 锁,表示当前获得kahadb读写权限的broker
2.JDBC存储
JDBC存储,即我们经常用到的MySQL、Oracle数据库。使用JDBC持久化方式,ActiveMQ会在数据库中创建3个表,分别是:activemq_msgs、activemq_acks、activemq_lock
- activemq_msgs 消息表,queue和topic都存在这个表中
- activemq_acks 存储持久订阅的消息和最后一个持久订阅接收的消息ID
- activemq_lock 锁表,用来确保某一时刻,只能有一个ActiveMQ Broker实例来访问数据库
2.1 JDBC存储的配置方式
2.1.1 持久化方式配置
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#MySql-DS" createTablesOnStartup="true"/>
</persistenceAdapter>
2.1.2 数据库bean配置(此处使用Druid连接池,activeMQ内置的的一个数据库连接池是dbcp连接池。我们使用了其他的第三方数据库技术,一定要在activemq的lib目录下引入相关的jar包和mysql-connector-java 的jar包)
<bean id="MySql-DS" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.204.201:3306/activemq?relaxAutoCommit=true"/>
<property name="username" value="root"/>
<property name="password" value="xxxxxx"/>
</bean>
2.1.3 添加Jar包依赖
druid-1.0.9.jar
mysql-connector-java-5.1.7-bin.jar
3.LevelDB存储
LevelDB持久化性能高于KahaDB,虽然目前默认持久化方式仍然是KahaDB,但是在ActiveMQ 5.9版本提供了基于LevelDB和ZooKeeper的数据复制方式,用于Master-Slave方式的首选数据复制方案。
不过,根据ActiveMQ官网对LevelDB的描述:LevelDB官方建议使用,但是不再支持。推荐使用KahaDB。具体为什么不推荐LevelDB原因不详。
3.1 LevelDB的配置方式
<persistenceAdapter>
<levelDBdirectory="activemq-levelDB"/>
</persistenceAdapter>
4.Memory存储(内存)
基于内存的消息存储,内存消息存储主要是存储所有的持久化消息到内存中。在broker标签中,配置 persistent="false" 表示不设置持久化存储,直接存储至内存中。
4.1 Memory存储的配置方式
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" persistent="false">
<!-- 内容省略 -->
</broker>
5.JDBC With ActiveMQ Journal存储
这种方式克服了JDBC存储的不足,JDBC每次消息过来,都需要去写库和读库。JDBC With ActiveMQ Journal存储,使用高速缓存写入技术,大大提高了性能。当消费者的消费速度能够及时跟上生产者消息的生产速度时,journal文件能够大大减少需要写入到DB中的消息。
举个例子,生产者生产了1000条消息,这1000条消息会保存到journal文件,如果消费者的消费速度很快的情况下,在journal文件还没有同步到DB之前,消费者已经消费了90%的以上的消息,那么这个时候只需要同步剩余的10%的消息到DB。
如果消费者的消费速度很慢,这个时候journal文件可以使消息以批量方式写到DB。
5.1 JDBC With ActiveMQ Journal存储的配置方式
1.将原来的标签注释掉
2. 添加如下标签:(数据库bean配置在这里也是需要的)
<persistenceFactory>
<journalPersistenceAdapterFactory dataSource="#MySql-DS" dataDirectory="active-journal"/>
</persistenceFactory>
在服务端循环发送消息,你可以看到数据时延迟同步到数据库的。