ActiveMQ存储的持久化机制

我们在使用原生ActiveMQ的API编程中,介绍ActiveMQ的使用过程中,在介绍其Point-to-Point(P2P) /点对点模式时,我们发现在该模式下消息时不会丢失的
在这里插入图片描述


那么这里是如果做到消息的持久化呢?ActiveMQ提供了几种持久化方式:

  1. AMQ消息存储,基于文件的存储方式,它具有写入速度快和容易恢复的特点。消息存储在一个个文件中,文件的默认大小为32M,如果一条消息的大小超过了32M,那么这个值必须设置大一点。当一个存储文件中的消息已经全部被消费,那么这个文件将被标识为可删除,在下一个清除阶段,这个文件被删除。AMQ适用于ActiveMQ5.3之前的版本。
  2. KahaDB消息存储,提供了容量的提升和恢复能力,是现在的默认存储方式;KahaDB是基于文件的本地数据库储存形式,虽然没有AMQ的速度快,但是它具有强扩展性,恢复的时间比AMQ短,从5.4版本之后KahaDB做为默认的持久化方式。
  3. JDBC消息存储,消息基于JDBC存储的。(JDBC Message Store with ActiveMQ Journal优化了JDBC Store消息存储)
  4. Memory消息存储,基于内存的消息存储,就是消息存储在内存中。这里没有动态的缓存存在,所以你必须注意设置你的broker所在的JVM和内存限制。这种方式的持久化消息只在当前JVM内有效,当重启JVM之后会丢失持久化的消息。



这里我们就来看一看ActiveMQ的conf路径下的activemq配置文件,如下:
在这里插入图片描述
在这里插入图片描述


从上述可以看出,ActiveMQ默认的持久化机制为KahaDB消息存储,所以即使你不配置任何的KahaDB参数信息,ActiveMQ也会启动KahaDB。这种情况下,KahaDB文件所在位置是你的ActiveMQ安装路径下的/data/kahadb子目录,如下:
在这里插入图片描述

  • db.data 它是消息的索引文件,本质上是B-Tree(B树),使用B-Tree作为索引指向db-*.log里面存储的消息
  • db.redo 用来进行消息恢复
  • db-*.log 存储消息内容。新的数据以APPEND的方式追加到日志文件末尾。属于顺序写入,因此消息存储是比较 快的。默认是32M,达到阀值会自动递增
  • lock 文件锁,写入当前获得kahadb读写权限的broker ,用于在集群环境下的竞争处理

系统中默认的kahadb的配置,只为我们配置的directory来指定文件的路径,其实我们还可以配置更多的属性,如下:

  1. director: KahaDB存放的路径,默认值activemq-data
  2. indexWriteBatchSize: 批量写入磁盘的索引page数量,默认值为1000
  3. indexCacheSize: 内存中缓存索引page的数量,默认值10000
  4. enableIndexWriteAsync: 是否异步写出索引,默认false
  5. journalMaxFileLength: 设置每个消息data log的大小,默认是32MB
  6. enableJournalDiskSyncs: 设置是否保证每个没有事务的内容,被同步写入磁盘,JMS持久化的时候需要,默认为true
  7. cleanupInterval: 在检查到不再使用的消息后,在具体删除消息前的时间,默认30000
  8. checkpointInterval: checkpoint的间隔时间,默认是5000
  9. ignoreMissingJournalfiles: 是否忽略丢失的消息日志文件,默认false
  10. checkForCorruptJournalFiles: 在启动的时候,将会验证消息文件是否损坏,默认false
  11. checksumJournalFiles: 是否为每个消息日志文件提供checksum,默认false
  12. archiveDataLogs: 是否移动文件到特定的路径,而不是删除它们,默认false
  13. directoryArchive: 定义消息已经被消费过后,移动data log到的路径,默认null
  14. databaseLockedWaitDelay: 获得数据库锁的等待时间(used by shared master/slave),默认10000
  15. maxAsyncJobs: 设置最大的可以存储的异步消息队列,默认值10000,可以和concurrent MessageProducers设置成一样的值。
  16. concurrentStoreAndDispatchTransactions: 是否分发消息到客户端,同时事务存储消息,默认true
  17. concurrentStoreAndDispatchTopics: 是否分发Topic消息到客户端,同时进行存储,默认true
  18. concurrentStoreAndDispatchQueues: 是否分发queue消息到客户端,同时进行存储,默认true



从ActiveMQ 4+版本开始,ActiveMQ就支持使用关系型数据库进行持久化存储——通过JDBC实现的数据库连接。可以使用的关系型数据库囊括了目前市面的主流数据库。


接下来我们就来将默认的KahaDB的存储机制改为JDBC的形式,首先我们在conf下的activemq.xml中,将默认配置的kahbdb改成jdbc,如下
在这里插入图片描述


然后我们就需要配置上述指定的名为dataSource的数据库连接,其实为Spring的配置是类似的,如下:
在这里插入图片描述

<bean id="dataSource" 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&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>      
	<property name="username" value="root"/>     
	<property name="password" value="root"/>   
</bean>

注:其中url属性值中配置的&amp;& 的转义字符,其中第一个属性relaxAutoCommit=true是必需的。



然后我们在本地数据中建立一个相同的数据库名activemq即口,然后就可以启动我们的ActiveMQ服务了,在启动ActiveMQ之前,我们需要在ActiveMQ安装目录下的lib目录下添加相关依赖jar包,就是用于上述创建和数据库的连接使用
在这里插入图片描述
在这里插入图片描述
这里版本没有太大要求,但是最好保持一致,比如这里我们引入dbcp2的包,那么配置文件中肯定也要是dbcp2.BasicDataSource



添加完依赖jar包后,就可以启动ActiveMQ了,然后我们就会发现在activemq数据库中多出了三种表,如下:
在这里插入图片描述


  • ACTIVEMAQ_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。
    在这里插入图片描述

  • ACTIVEMQ_MSGS,用于存储消息,Queue和Topic都存储在这个表中
    在这里插入图片描述
    • ID: 自增的数据库主键
    • CONTAINER: 消息的目的地Destination
    • MSGID_PROD: 消息发送者在客户端的主键
    • MSGID_SEQ: 是发送消息的顺序,MSGID_PROD + MSGID_SEQ可以组成JMS的MessageID
    • EXPIRATION: 消息的过期时间,存储的是从1970-01-01到现在的毫秒数
    • MSG: 消息本体的java序列化对象的二进制数据
    • PRIORITY: 优先级,从0-9,数值越大优先级越高

这里我们在Point-to-Point(P2P) /点对点模式下,来启动一个消息生成者,但是不启动消费者,然后来看看ACTIVEMQ_MSGS表的信息,如下:
在这里插入图片描述
这里我们就可以看到消息生成者发送的三条数据,消费者还未进行消费,就可以在ACTIVEMQ_MSGS查看到信息,然后我们在启动消息的消费者,该表中的三条数据就会被消费掉了(即表中数据被删除)




JDBC Message Store with ActiveMQ Journal可以看做优化版的JDBC存储,这种方式克服了JDBC Store的不足,JDBC存储每次消息过来,都需要去写库和读库。而JDBC Message Store with ActiveMQ Journal使用延迟存储数据到数据库,当消息来到时先缓存到文件中,延迟后才写到数据库中。


当消费者的消费速度能够及时跟上生产者消息的生产速度时,journal文件能够大大减少需要写入到DB中的消息。 举个例子,生产者生产了1000条消息,这1000条消息会保存到journal文件,如果消费者的消费速度很快的情况 下,在journal文件还没有同步到DB之前,消费者已经消费了90%的以上的消息,那么这个时候只需要同步剩余的 10%的消息到DB。 如果消费者的消费速度很慢,这个时候journal文件可以使消息以批量方式写到DB。


其配置如下:
在这里插入图片描述

<persistenceFactory>
	<journalPersistenceAdapterFactory journalLogFiles="4" journalLogFileSize="32768" useJournal="true" useQuickJournal="true" dataSource="#dataSource" dataDirectory="activemq-data"/>
</persistenceFactory>



Memory内存消息存储主要是存储所有的持久化的消息在内存中。这里没有动态的缓存存在,所以你必须注意设置你的broker所在的JVM和内存限制。


这种方式的持久化消息只在当前JVM内有效,当重启JVM之后会丢失持久化的消息。


配置方式如下:只需要将persistent属性设为false即可
在这里插入图片描述




还有一种就是AMQ消息存储,它是一个基于文件、事务存储设计为快速消息存储的一个结构,该结构是以流的形式来进行消息交互的。

其配置如下:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章