ActiveMQ学习笔记-09——ActiveMQ的消息存储和持久化
参考:【尚硅谷ActiveMQ教程(MQ消息中间件快速入门)
-
种类
-
AMQ Message Store
- 基于文件的存储方式,是以前的默认存储消息存储,现在不用了
-
KahaDB消息存储(独立)
-
基于日志的存储方式,从5.4版本之后开始的默认持久化插件
-
官网:http://activemq.apache.org/kahadb
-
消息存储使用一个事务日志和仅仅用一个索引文件来存储它所有的地址。
-
默认配置
<persistenceAdapter> <kahaDB directory="${activemq.data}/kahadb"/> </persistenceAdapter>
-
文件说明
默认路径:
${activemq.data}/kahadb
db-<Number>.log
KahaDB存储消息到预定大小的数据记录文件中,文件命名为db-<Number>.log
。当数据文件已满时,一个新的文件会随之创建,number数值也会随之递增,它随着消息数量的增多,如每32M一个文件,文件名按照数字进行编号,如db-1.log、db-2.log……。当不再有引用到数据文件中的任何消息时,文件会被删除或归档。db.data
该文件包含了持久化的B-Tree索引,索引了消息数据记录中的消息,它是消息的索引文件,本质上是B-Tree,使用B-Tree作为索引指向db-<Number>.log
里面存储的消息。db.free
当前db.data
文件里哪些页面是空闲的,文件具体内容是所有空闲页的ID。db.redo
用来进行消息恢复,如果KahaDB消息存储中强制退出后启动,用于恢复B-Tree索引。lock
文件锁,表示当前获得kahadb读写权限的broker
-
-
LevelDB消息存储
-
从5.8版本之后引进,和KahaDB非常相似,也是基于文件的本地数据库存储形式,但是它提供比KahaDB更快的持久性。
-
不使用自定义B-Tree实现来索引预写日志,而是使用基于LevelDB的索引
-
默认配置
<persistenceAdapter> <levelDB directory="activemq-data"/> </persistenceAdapter>
-
-
JDBC消息存储
-
说明
- 使用第三方数据库存储数据
-
使用
-
添加mysql数据库的驱动包到lib文件夹
-
修改activemq.xml为jdbcPersistenceAdapter配置
<persistenceAdapter> <jdbcPersistenceAdapter dataSource="#mysql-ds"/> </persistenceAdapter>
- dataSource指定将要引用的持久化数据库的bean名称
- createTableOnStartup是否在启动的时候创建数据表,默认值是true,这样每次启动都会去创建数据表了,一般是第一次启动的时候设置为true之后改成false。
-
添加数据库连接池配置,添加在末尾
</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://127.0.0.1:3306/activemq?relaxAutoCommit=true"/> <property name="username" value="activemq"/> <property name="password" value="activemq"/> <property name="poolPreparedStatements" value="true"/> </bean>
-
数据库建库建表
-
新建一个名为activemq的数据库
CREATE DATABASE activemq;
-
启动ActiveMQ自动生成三张表
-
三张表说明
- ACTIVEMQ_MSGS
- 消息表,queue和topic都存在里面
- 结构
ID
:自增的数据库主键CONTAINER
:消息的DestinationMSGID_PROD
:消息发送者的主键MSG_SEQ
:发送消息的顺序,MSGID_PROD
+MSG_SEQ
可以组成JMS的MessageIDEXPIRATION
:消息的过期时间,存储的是从1970-01-01到现在的毫秒数MSG
:消息本体的Java序列化对象的二进制数据PRIORITY
:优先级,从0-9,数值越大优先级越高
- ACTIVEMQ_ACKS
- 存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这张表保存
- 存储持久订阅的信息和最后一个持久订阅接收的消息ID
- 结构
CONTAINER
:消息的DestinationSUB_DEST
:如果是使用Static集群,这个字段会有集群其他系统的信息CLIENT_ID
:每个订阅者都必须有一个唯一的客户端ID用以区分SUB_NAME
:订阅者名称SELECTOR
:选择器,可以选择只消费满足条件的消息。条件可以用自定义属性实现,可支持多属性AND和OR操作LAST_ACKED_ID
:记录消费过的消息的ID
- ACTIVEMQ_LOCK
- 在集群环境中才有用,只有一个Broker可以获得消息,称为Master Broker,其他只能作为备份等待Master Broker不可用,才可能成为下一个Master Broker。
- 这个表用于记录那个Broker是当前的Master Broker
- ACTIVEMQ_MSGS
-
-
-
总结
- queue
- 在没有消费者的情况下会将消息保存到ACTIVEMQ_MSGS表中,只要有任意一个消费者已经消费过了,消费之后这些消息将会被立即删除。
- topic
- 一般是先启动消费者订阅再生产的情况下会将消息保存到ACTIVEMQ_ACKS中。
- queue
-
开发中的坑
- 数据库jar包
- 需要使用到的相关jar包放置到ActiveMQ安装路径下的lib目录。mysql-jdbc驱动以及数据库连接池的jar包
- createTablesOnStartup属性
- 在jdbcPersistenceAdapter标签中设置了createTablesOnStartup属性为true时,在第一次启动ActiveMQ时,ActiveMQ服务节点会自动创建所需要的数据表,启动完成后可以去掉这个属性,或者更改createTablesOnStartup属性为false。
- 下划线
- “java.lang.IllegalStateException:BeanFactory not initialized or already closed”
- 操作系统机器名有“_”。更改机器名重启即可
- 数据库jar包
-
-
JDBC Message store with ActiveMQ Journal
-
说明
- 克服了JDBC Store的不足
- 使用高速缓存写入技术,大大提高了性能
- 当消费者的消费速度能够及时跟上生产者消息产生速度时,journal文件能够大大减少需要写入DB中的消息
-
配置
<persistenceFactory> <journalPersistenceAdapterFactory journalLogFiles="4" journalLogFileSize="32768" useJournal="true" useQuickJournal="true" dataSource="#mysql-ds" dataDirectory="activemq-data" /> </persistenceFactory>
-
-
-
总结
- 演变
- 从最初的AMQ Message Store方案到V4版本中推出的High performance journal(高性能事务支持)附件,并且同步推出了关于关系型数据库的存储方案。V5.3版本中又推出了对KahaDB的支持(V5.4版本后成为ActiveMQ默认的持久化方案),后来V5.8版本开始支持LevelDB,到现在,V5.9版本提供了标准的Zookeeper+LevelDB集群化方案。
- 简单对比
- AMQ:基于日志文件
- KahaDB:基于日志文件,从5.4版本开始默认的持久化插件
- JDBC:基于第三方数据库
- LevelDB:基于文件的本地数据库存储,从5.8版本之后推出的LevelDB性能高于KahaDB
- Replicated LevelDB Store:从5.9版本提供了基于LevelDB和Zookeeper的数据复制方式,用于Master-slave方式的首选方案。
- 持久化的逻辑
- 在发送者将消息发送出去后,消息中心首先将消息存储到本地数据文件、内存数据库或者远程数据库等,然后试图将消息发送给接收者,发送成功则将消息从存储中删除,失败则继续尝试。
- 消息中心启动后首先要检查指定的存储位置,如果有未发送成功的消息,则需要把消息重新发送出去。
- 演变