消息的存储方式
Queue消息模型
采用存储采用先进先出(FIFO),一个消息只能被一个消费者消费,当消息被确认消费之后才会被删除。
Topic消息模型
每个订阅者获取的消息实际是消息的一个副本,只有一个消息副本会被存储,MQ 提供了一个指针来指向消息存储并且分发消息副本到订阅者,消息直到所有的持久化订阅者都被接收才能被删除。
持久化存储
- KahaDB消息存储
- AMQ消息存储
- JDBC消息存储
- 内存消息存储
KahaDB
默认的持久化方式,KahaDB存储是一个基于文件的快速存储消息,所有的消息顺序的添加到一个日志文件中,同时有另一个索引文件记录执行这些日志到存储地址,还有一个事务日志用于消息的恢复操作。
特性
- 日志形式存储消息;
- 消息索引以B-Tree结果存储,可以快速更新;
- 完全支持JMS事务;
- 支持多种恢复机制,kahadb可以限制每个数据文件的大小。
配置
在activemq.xml中配置如下:
<broker brokerName="broker" persistent="true" useShutdownHook="false">
<persistenceAdapter>
<!--directory:保存数据的目录;journalMaxFileLength:保存消息的文件大小 -->
<kahaDB directory="${activemq.data}/kahadb" journalMaxFileLength="16mb"/>
</persistenceAdapter>
</broker>
目录结构

当有消费者时,缓存用于临时存储,消息会被发送给消费者,同时将安排存储。如果消息被很快确认,就不需要写入磁盘。如果消息已经写入磁盘,后续有消费者成功消费了此消息,将其标记为可删除,系统会周期性的清除或者归档日志文件。
- db.data:存放B-Tree indexs;
- db.redo:存放redo file,用于恢复B-Tree indexs;
- db log files:用于存储消息,当log日志到了指定的大小,会创建一个新的,当log日志中的消息都被删除,改日志文件将会删除;
存储原理

- Cache:用于临时存储,消息会被发送给消费者,同时将安排存储。如果消息被很快确认,就不需要写入磁盘。
- BTree Indexes:保存在磁盘上,称为Metadata Store,对应的是db.data文件。它是对Data Logs以B树的形式索引。消息服务器可以通过此文件快速的重启恢复,因为它是消息的索引,可以恢复出每条消息的location。
- Data Logs:对应文件db-XX.log,以日志的形象存储生产者生产的消息。
- Redo log:对应db.redo,用于在非正常关机情况下维护索引完整性。
Metadata Store和Metadata Cache需要保证同步,同步的过程叫做check point。
AMQ存储
和KahaDB一样,AMQ 也是一个文件型数据库,消息信息最终是存储在文件中。内存中也会有缓存数据。
为了提升性能,创建消息的主键索引,进一步提升性能。同时由于AMQ回味每一个Destination创建一个索引,如果使用大量的Queue,索引文件将占用很多磁盘空间,同时Broker奔溃,索引重建的过程非常慢。所以,Destination的数量较少,消息吞吐量是应用程序的主要需求时可以选用此方式存储。
配置
配置方式 conf/activemq.xml:
<persistenceAdapter>
<!--AMQ directory:数据存储路径 syncOnWrite:是否同步写入 maxFileLength:日志文件大小 -->
<amqPersistenceAdapter
directory="${activemq.data}/kahadb"
syncOnWrite="true"
maxFileLength="10mb" />
</persistenceAdapter>
虽然 AMQ 性能略高于 Kaha DB 方式,但是由于其重建索引时间过长,而且索引文件 占用磁盘空间过大,所以已经不推荐使用。
JDBC存储
支持通过 JDBC 将消息存储到关系数据库,性能上不如文件存储,能通过关系型数据库查询到消息的信息。
数据库默认会创建3个表,每个表的作用:
- activemq_msgs:queue和topic的消息都存在这个表中
- activemq_acks:用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存
- activemq_lock:跟kahadb的lock文件类似,确保数据库在某一时刻只有一个broker在访问(集群环境中才有用)
配置方式
配置文件的Beans标签中添加:
<!--配置数据源-->
<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
<property name="maxActive" value="200"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
<!--dataSource 指定持久化数据库的 bean,createTablesOnStartup 是否在启动的时候创建数据表,默认值是 true,这样每次启动都会去创建数据表了,一般是第一次启动的时候设置为 true,之后改成 false。-->
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="false"/>
</persistenceAdapter>
内存存储
基于内存的消息存储,就是消息存储在内存中。必须注意JVM使用情况以及内存限制,适用于一些能快速消费的数据量不大的小消息,当MQ关闭或者宕机,未被消费的内存消息会被清空。
配置方式 设置 broker属性值 persistent=“false”:表示不设置持久化存储,直接存储到内存中在broker标签处设置.
<broker brokerName="test-broker" persistent="false" xmlns="http://activemq.apache.org/schema/core">
<transportConnectors>
<transportConnector uri="tcp://localhost:61635"/>
</transportConnectors>
</broker>
本文详细介绍了ActiveMQ的消息存储方式,包括Queue和Topic消息模型,以及KahaDB、AMQ存储、JDBC存储和内存存储的特性、配置和工作原理。重点讨论了KahaDB作为默认持久化方式的存储结构和恢复机制。
1万+

被折叠的 条评论
为什么被折叠?



