ActiveMq消息持久化
消息持久化
消息持久化是保证消息不丢失的重要方式!!!
ActiveMQ提供了以下三种的消息存储方式:
(1) Memory 消息存储-基于内存的消息存储。
(2) 基于日志消息存储方式,KahaDB是ActiveMQ的默认日志存储方式,它提供了容量的提升和恢复
能力。
(3) 基于JDBC的消息存储方式-数据存储于数据库(例如:MySQL)中。
ActiveMQ持久化机制流程图:
KahaDB存储
消息存储使用一个事务日志和仅仅用一个索引文件来存储它所有的地址:(文件在apache-activemq\data\kahadb下)
1、db-
2、db.data文件包含了持久化的BTree索引,索引了消息数据记录中的消息,它是消息的索引文件,本质上是B-Tree(B树),使用B-Tree作为索引指向db-
3、db.free文件表示当前db.data文件哪些页面是空闲的,文件具体内容是所有空闲页的ID。
4、db.redo文件是用来进行消息恢复,如果KahaDB消息存储在强制退出后启动,用于恢复BTree索引。
5、lock文件表示当前获得KahaDB读写权限的broker。
可以更改的属性:
官网说明:http://activemq.apache.org/kahadb
属性 | 默认 | 说明 |
---|---|---|
archiveCorruptedIndex |
false |
如果true ,启动时发现的损坏索引将被归档(未删除)。 |
archiveDataLogs |
false |
如果true ,将邮件数据日志移动到存档目录而不是删除它。 |
checkForCorruptJournalFiles |
false |
如果true ,将在启动时检查损坏的日志文件并尝试恢复它们。 |
checkpointInterval |
5000 |
检查日志之前的时间(ms)。 |
checksumJournalFiles |
true |
为日志文件创建校验和。需要存在校验和才能使持久性适配器能够检测损坏的日志文件。在ActiveMQ 5.9.0之前:默认为false 。 |
cleanupInterval |
30000 |
连续检查之间的间隔(以毫秒为单位),用于确定哪些日志文件(如果有)可以从邮件存储中删除。符合条件的日志文件是没有未完成引用的文件。 |
compactAcksAfterNoGC |
10 |
从ActiveMQ 5.14.0开始:当启用确认压缩功能时,此值控制必须完成的存储GC周期数,在压缩逻辑被触发之前不会清除其他文件,从而可能将跨日志文件的旧确认压缩到新日志中文件。值设置越低,压缩可能发生得越快,如果经常运行,可能会影响性能。 |
compactAcksIgnoresStoreGrowth |
false |
从ActiveMQ 5.14.0开始:当启用确认压缩功能时,此值控制当存储仍在增长时是否运行压缩,或者是否仅在存储停止增长时(由于达到空闲或存储限制而发生)。如果启用,则无论商店仍有空间或处于活动状态,压缩都会运行,这会降低整体性能,但会更快地回收空间。 |
concurrentStoreAndDispatchQueues |
true |
启用将Queue消息分派给感兴趣的客户端以与消息存储同时发生。 |
concurrentStoreAndDispatchTopics |
false |
允许向感兴趣的客户端分派主题消息以与消息存储同时发生。建议不要启用此属性。 |
directory |
activemq-data |
用于存储消息存储数据和日志文件的目录的路径。 |
directoryArchive |
null |
定义目录以将数据日志移动到它们包含的所有消息时。 |
enableAckCompaction |
true |
从ActiveMQ 5.14.0:此设置控制商店是否将定期压缩仅包含消息确认的旧日记日志文件。通过将这些旧的确认压缩到新的日志日志文件中,可以删除较旧的文件以释放空间并允许消息存储继续操作而不会达到存储大小限制。 |
enableIndexWriteAsync |
false |
如果true ,索引是异步更新的。 |
enableJournalDiskSyncs |
true |
确保每个日志写入后跟一个磁盘同步(JMS持久性要求)。从ActiveMQ 5.14.0开始,不推荐使用此属性。从ActiveMQ 5.14.0:看journalDiskSyncStrategy 。 |
ignoreMissingJournalfiles |
false |
如果true ,忽略日记文件丢失的报告。 |
indexCacheSize |
10000 |
内存中缓存的索引页数。 |
indexDirectory |
从ActiveMQ 5.10.0开始:如果设置,则配置将存储KahaDB索引文件(db.data 和 db.redo )的位置。如果未设置,索引文件将存储在directory 属性指定的目录中 。 |
|
indexWriteBatchSize |
1000 |
批量写入的索引数。 |
journalDiskSyncInterval |
1000 |
何时执行磁盘同步的时间间隔(ms) journalDiskSyncStrategy=periodic 。只有在自上次磁盘同步或日志转到新日志文件后对日志进行了写入时,才会执行同步。 |
journalDiskSyncStrategy |
always |
从ActiveMQ 5.14.0:此设置配置磁盘同步策略。可用的同步策略列表(按安全性降低和性能提高的顺序):always 确保每个日志写入后跟一个磁盘同步(JMS持久性要求)。这是最安全的选项,但也是最慢的选项,因为它需要在每次写入消息后进行同步。这相当于不推荐使用的属性 enableJournalDiskSyncs=true 。periodic 磁盘将以设定的时间间隔(如果发生写入)而不是在每次日志写入之后同步,这将减少磁盘上的负载并且应该提高吞吐量。滚动到新的日志文件时,磁盘也将同步。默认间隔为1秒。默认间隔提供非常好的性能,同时比更安全 never 磁盘同步,因为数据丢失的最大值限制为1秒。请参阅journalDiskSyncInterval 更改磁盘同步的频率。never 永远不会显式调用同步,并且操作系统将刷新到磁盘。这相当于设置deprecated属性enableJournalDiskSyncs=false 。这是最快的选择,但是最不安全,因为无法确保何时将数据刷新到磁盘。因此,代理失败时可能会发生消息丢失。 |
journalMaxFileLength |
32mb |
提示设置消息数据日志的最大大小。 |
maxAsyncJobs |
10000 |
将等待存储排队的异步消息的最大数量(应与并发MessageProducers的数量相同)。 |
preallocationScope |
entire_journal |
从ActiveMQ 5.14.0:此设置配置如何预分配日记帐数据文件。默认策略使用appender线程在首次使用时预先分配日志文件。 entire_journal_async 将在单独的线程中提前使用preallocate。none 禁用预分配。在SSD上,使用 entire_journal_async 避免在首次使用时延迟写入等待预分配。注意:在HDD上,磁盘的额外线程争用会产生负面影响。因此使用默认值。 |
preallocationStrategy |
sparse_file |
从ActiveMQ 5.12.0:此设置配置代理在需要新日志文件时尝试预分配日志文件的方式。sparse_file - 设置文件长度,但不会用任何数据填充它。os_kernel_copy - 将预分配委派给操作系统。zeros - 每个预分配的日志文件只包含0x00 整个文件。 |
storeOpenWireVersion |
11 |
确定封送到KahaDB日志的OpenWire命令的版本。在ActiveMQ 5.12.0之前:默认值为6 。代理的某些功能取决于较新协议修订版中存储在OpenWire命令中的信息,如果将商店版本设置为较低值,这些功能可能无法正常工作。在许多情况下,代理版本大于5.9.0的KahaDB存储仍然可以被代理读取,但会导致代理继续使用较旧的商店版本,这意味着较新的功能可能无法按预期工作。对于在ActiveMQ 5.9.0之前的版本中创建的KahaDB存储,需要手动设置storeOpenWireVersion="6" 以便启动代理而不会出现错误。 |
测试:把mq直接杀死,然后已经消费的消息不在了,未读的还存在
[root@localhost data]# ll
总用量 12
-rw-r--r--. 1 root root 6026 10月 14 11:07 activemq.log
-rw-r--r--. 1 root root 6 10月 13 10:29 activemq.pid
-rw-r--r--. 1 root root 0 10月 13 10:29 audit.log
drwxr-xr-x. 2 root root 64 10月 13 10:29 kahadb
[root@localhost data]# ps -ef |grep activemq
root 22343 1 0 10月13 ? 00:04:59 /usr/bin/java -Xms64M -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/root/apache-activemq-5.14.0//conf/login.config -Dcom.sun.management.jmxremote -Djava.awt.headless=true -Djava.io.tmpdir=/root/apache-activemq-5.14.0//tmp -Dactivemq.classpath=/root/apache-activemq-5.14.0//conf:/root/apache-activemq-5.14.0//../lib/: -Dactivemq.home=/root/apache-activemq-5.14.0/ -Dactivemq.base=/root/apache-activemq-5.14.0/ -Dactivemq.conf=/root/apache-activemq-5.14.0//conf -Dactivemq.data=/root/apache-activemq-5.14.0//data -jar /root/apache-activemq-5.14.0//bin/activemq.jar start
root 25880 20668 0 14:09 pts/0 00:00:00 grep --color=auto activemq
[root@localhost data]# kill -9 22343
[root@localhost data]# ll
总用量 12
-rw-r--r--. 1 root root 6026 10月 14 11:07 activemq.log
-rw-r--r--. 1 root root 6 10月 13 10:29 activemq.pid
-rw-r--r--. 1 root root 0 10月 13 10:29 audit.log
drwxr-xr-x. 2 root root 64 10月 13 10:29 kahadb
[root@localhost data]# cd ..
[root@localhost apache-activemq-5.14.0]# ll
总用量 15872
-rwxr-xr-x. 1 root root 16195019 8月 2 2016 activemq-all-5.14.0.jar
drwxr-xr-x. 5 root root 147 10月 13 10:23 bin
drwxr-xr-x. 2 root root 4096 10月 13 10:23 conf
drwxr-xr-x. 3 root root 77 10月 13 10:29 data
drwxr-xr-x. 2 root root 76 10月 13 10:23 docs
drwxr-xr-x. 7 root root 71 8月 2 2016 examples
drwxr-xr-x. 6 root root 4096 10月 13 10:23 lib
-rw-r--r--. 1 root root 40580 8月 2 2016 LICENSE
-rw-r--r--. 1 root root 3334 8月 2 2016 NOTICE
-rw-r--r--. 1 root root 2610 8月 2 2016 README.txt
drwxr-xr-x. 4 root root 136 10月 13 10:29 tmp
drwxr-xr-x. 6 root root 95 10月 13 10:23 webapps
drwxr-xr-x. 3 root root 18 10月 13 10:23 webapps-demo
[root@localhost apache-activemq-5.14.0]# cd bin
[root@localhost bin]# ./activemq start
INFO: Loading '/root/apache-activemq-5.14.0//bin/env'
INFO: Using java '/usr/bin/java'
INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details
INFO: pidfile created : '/root/apache-activemq-5.14.0//data/activemq.pid' (pid '25920')
测试图
JDBC消息存储
1、将原来的kshadb的持久化数据的方式更改为jdbc:
<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.1.104:3306/db_activemq?relaxAutoCommit=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<persistenceAdapter>
<!--<kahaDB directory="${activemq.data}/kahadb"/>-->
<jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="true"/>
</persistenceAdapter>
注意:dataSource指定将要引用的持久化数据库的bean名称,createTablesOnStartup表示是否在启动时创建数据表,默认值为true,这样每次启动都会创建数据表,一般是第一次启动的时候设置为true之后改为false。
自动创建的三张数据表说明:
- activemq_msgs用于存储消息,Queue和Topic都存储在这个表中:
ID:自增的数据库主键
CONTAINER:消息的Destination
MSGID_PROD:消息发送者客户端的主键
MSG_SEQ:是发送消息的顺序,MSGID_PROD+MSG_SEQ可以组成JMS的MessageID
EXPIRATION:消息的过期时间,存储的是从1970-01-01到现在的毫秒数
MSG:消息本体的Java序列化对象的二进制数据
PRIORITY:优先级,从0-9,数值越大优先级越高 - activemq_acks用于存储订阅关系。如果是持久化Topic,订阅者和服务器的订阅关系在这个表保存:
主要的数据库字段如下:
CONTAINER:消息的Destination
SUB_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。
- 如果是queue模式,在没有消费者的情况下会将消息保存到activemq_msgs表中,只要有任意一个消费者已经消费过,相应的消息将会立即被删除。
- 如果是topic模式,一般是先启动消费订阅然后再生产的情况下会将消息保存到activemq_acks表中。