ActiveMQ(五)---消息存储

1. 引子

在Activemq当中,消息大概会经历以下3个步骤:

其中每个步骤出错都有可能导致消息丢失,如在第2步,消息还在消息服务器的内存当中没有被消费,此时消息服务被kill掉了,内存中的消息自然就丢失了。考虑到这种情况,ActiveMQ引入了消息持久化的概念,既将通过文件或者数据库的形式消息保存到磁盘中。

2. ActiveMQ的几种容量

在ActiveMQ的控台的首页中,有3个关于容量使用百分比的监控,如下图所示:

它们对应着ActiveMQ配置文件中的以下配置:

<systemUsage>
    <systemUsage>
        <memoryUsage>
            <memoryUsage percentOfJvmHeap="70" />
        </memoryUsage>
        <storeUsage>
            <storeUsage limit="100 gb"/>
        </storeUsage>
        <tempUsage>
            <tempUsage limit="50 gb"/>
        </tempUsage>
    </systemUsage>
</systemUsage>

memoryUsage:设置ActiveMQ节点的可用内存限制。其中的percentOfJvmHeap属性表示使用JVM maxmemory值的百分比进行设置,除了这个属性以外,还可以使用limit属性进行固定容量设置,例如:limit=”1000 mb”。这些内存容量将供所有队列使用。

storeUsage:设置ActiveMQ节点用于存储持久化消息的可用磁盘空间。limit属性必须要进行设置。如果使用数据库存储方案,这个属性就不会起作用了。

tempUsage:在ActiveMQ 5.X版本中,一旦ActiveMQ服务节点存储的消息达到了memoryUsage的限制,NON_PERSISTENT Message就会被转储到 temp store区域。虽然说过NON_PERSISTENT Message不进行持久化存储,但是ActiveMQ为了防止“数据洪峰”出现时NON_PERSISTENT Message大量堆积致使内存耗尽的情况出现,还是会将NON_PERSISTENT Message写入到磁盘的临时区域——temp store。这个子标记就是为了设置这个temp store区域的可用磁盘空间限制。

3. 消息存储的配置

在activemq(version:5.15.8)的默认配置文件conf\activemq.xml中,有如下一段配置:

<persistenceAdapter>
    <kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>

可以看到默认的存储引擎是基于文件的kahaDB,文件默认保存的路径为:${activemq.data}/kahadb

4. 分类

ActiveMQ中,支持的消息存储有如下几种:

  • LevelDB
  • KahaDB
  • AMQ Message Store
  • JDBC
  • Memory

其中LevelDB、KahaDB和AMQ Message Store都是基于文件的存储,JDBC使用关系型数据来存储,Memory将消息存储在内存当中。

5. LevelDB

LevelDB使用自定义的索引替代B-Tree索引,其性能优于KahaDB。
LevelDB是ActiveMQ5.8版本加入的存储引擎,并在ActiveMQ5.9版本中还提供了基于LevelDB和Zookeeper的数据复制方式,作为Master-Slave数据复制的首选方案。不过在ActiveMQ的官网中有以下一段话:

Warning

The LevelDB store has been deprecated and is no longer supported or recommended for use. The recommended store is KahaDB

不知道因为什么原因,ActiveMQ官方不再推荐使用LevelDB,而是建议使用KahaDB。更多关于LevelDB的介绍请参考 LevelDB Store

6. KahaDB

KahaDB是一个专门针对消息持久化的解决方案,它对典型的消息使用模式进行了优化。在kahaDB中,消息数据被追加到 data logs中。KahaDB依然是ActiveMQ默认使用的存储方案

6.1. KahaDB基本结构

在KahaDB的存储目录下,可以看到以下文件:

KahaDB存储所用到的文件

db.data:消息的索引文件,本质上是B-Tree的实现,指向db-*.log中存储的消息;
db.redo:重做记录,主要用来消息的恢复;
db-*.log:存储具体的消息,当文件大小超过journalMaxFileLength(默认值32MB)则创建一个新的日志文件来保存消息。
lock:文件锁

KahaDB的底层原理如下所示

KahaDB原理图

从上图中可以看到,BTree索引指向了具体的消息存储。另外为了效率,当消息存在活跃的消费者时,消息会临时保存在Cache(可以理解成内存)当中,如果消息被及时消费的话,则消息直接被删除或归档而不需要回写到磁盘当中。

内存(Cache)中的消息和BTree信息需要定期(通过checkpointInterval属性设置时间间隔)同步到文件当中,而这个同步过程称为:check point

6.2. KahaDB的配置

下面介绍一些KahaDB常见的配置,更多请参见:KahaDB

  • journalMaxFileLength:指定日志文件的大小,默认32M;
  • archiveDataLogs:默认false,如果设置成true则表示当消息被消费之后,消息不删除而是归档;
  • checkpointInterval:checkpoint执行的时间的间隔,单位ms,默认5s;
  • indexCacheSize:内存中缓存的索引页数量,默认10000;
  • journalDiskSyncStrategy:磁盘同步策略,取代ActiveMQ 5.14.0之前的enableJournalDiskSyncs配置。有以下3种策略
    • always:默认的策略,每次消息写入到日志文件中都同步到磁盘中,性能最差,但最不容易丢消息
    • periodic:每隔一段时间将写入到日志文件中的消息同步到磁盘,默认的时间间隔为1分钟,通过journalDiskSyncInterval指定时间间隔。
    • never:不显式调用磁盘同步,而是依赖操作系统自身的磁盘同步机制。这个策略性能最好,但是容易丢消息。
  • directory:消息持久化存储的目录。

7. JDBC消息存储

除了将消息持久化到文件中,您还可以将消息保存数据当中,ActiveMQ的JDBC消息存储引擎支持市面上主流的关系型数据库。

7.1 配置JDBC存储

  1. 以MySQL为例进行说明,首先需要将连接MySQL所需要的驱动包、数据库连接池包(这里使用c3p0)放入${activemq.home}/lib目录下
  1. 在ActiveMQ的配置文件中,进行如下的配置:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
    
    <persistenceAdapter>
        <jdbcPersistenceAdapter dataSource="#mysql-ds"/>
    </persistenceAdapter>

</broker>

<bean id="mysql-ds"
    class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl"
    value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true&amp;serverTimezone=UTC"/>
    <property name="user" value="root"/>
    <property name="password" value="***"/>
    <property name="maxPoolSize" value="200"/>
</bean>

7.2 表结构

消息存储方式改成JDBC后,首次启动ActiveMQ会自动在数据库中创建3张表。

jdbc存储对应的表

下面具体看看这3张表的结构以及作用

activemq_acks
activemq_acks表主要用于记录持久化订阅者的相关信息,它的字段信息如下所示:

column name comment
CONTAINER 消息的目的地
SUB_DEST 持久订阅者的目的地
CLIENT_ID 持久化订阅者的标识
SUB_NAME 持久化订阅者的名称
SELECTOR 持久化订阅者的选择器
LAST_ACKED_ID 订阅者收到的最后一个消息的序号
PRIORITY 优先级
XID

activemq_lock
activemq_lock表用来保证同一时间只会有一个ActiveMQ实例可以访问数据库,主要用在集群的场景。只有获取到锁的ActiveMQ才能访问数据库,没有获取到锁的ActiveMQ等待锁的释放。

column name comment
ID 主键
TIME 锁被获取的时间
BROKER_NAME 获取到锁的broker名称

activemq_msgs
消息保存到activemq_msgs表中,activemq_msgs表的字段信息如下:

column name comment
ID 主键
CONTAINER 持久订阅者的目的地
MSGID_PROD 生产者消息的ID
MSGID_SEQ MSGID_PROD+MSGID_SEQ=JMSMessageID
EXPIRATION 消息过期时间
MSG 序列化的消息
PRIORITY 优先级
XID

7.3 结合日志使用JDBC消息存储(jdbc with journal )

使用数据库来持久化消息的性能并不是很理想,一般会和日志结合使用以提升性能。

<beans>
  <broker brokerName="test-broker" xmlns="http://activemq.apache.org/schema/core">
    <persistenceFactory>
    <journalPersistenceAdapterFactory journalLogFiles="4" journalLogFileSize="32768"
      useJournal="true" useQuickJournal="true" dataSource="#mysql_ds" dataDirectory="activemq-data">
    </persistenceFactory>
  </broker>
      
    <bean id="mysql-ds"
    class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl"
    value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true&amp;serverTimezone=UTC"/>
    <property name="user" value="root"/>
    <property name="password" value="***"/>
    <property name="maxPoolSize" value="200"/>
    </bean>
</beans>

Tips:一般情况下,推荐使用jdbc with journal 。不过主从架构的时候不推荐这种用法,因为在master的消息还存储本地日志还没来得及同步到数据库时,master挂了会导致消息丢失。

8. Memory和AMQ Message Store

8.1 Memory

Memory存储主要是存储所有的消息在内存中,这种性能虽然是最好的,但也是最容易丢消息的。一般不推荐在生产中使用。

具体配置

<?xml version="1.0" encoding="UTF-8"?>
<beans>
  <broker brokerName="test-broker" persistent="false"
    xmlns="http://activemq.apache.org/schema/core">
    <transportConnectors>
      <transportConnector uri="tcp://localhost:61635"/>
    </transportConnectors>
  </broker>
</beans>

8.2 AMQ Message Store

AMQ Message Store是ActiveMQ5.0缺省的持久化存储,它是一个基于文件、事务存储设计为快速消息存储的一个结构,该结构是以流的形式来进行消息交互的。

参考

[1].JMS学习(七)-ActiveMQ消息的持久存储方式之KahaDB存储
[2].《ActiveMQ in action》- Chapter 5 ActiveMQ message storage
[3]. ActiveMQ官网教程:Persistence

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 个人专题目录[https://www.jianshu.com/p/140e2a59db2c] 一、JMS简介 全称...
    Java及SpringBoot阅读 2,067评论 0 10
  • 为了避免意外宕机以后丢失信息,需要做到重启后可以恢复消息队列,消息系统一般都会采用持久化机制。ActiveMQ的消...
    曹振华阅读 2,903评论 0 4
  • 小蛋仔熟熟的睡着了,黑黝黝的脸蛋上还挂着泪痕,时不时鼻子还抽泣一下,伴随着长长的喘息声。 亲了他一口,娟子就麻利地...
    烟花点点阅读 327评论 1 2
  • 惊心不断,噩梦连连 没能早起 这里有很多人疼爱 依旧不是家 如果有人喊我回去 就好了 可没有 如果有 我会很感动 ...
    小肥肉哎阅读 208评论 0 0
  • 昨晚开了月总结大会之后,通过Tom教练的细心调配,学员分组学习,今天感觉各个群里的气氛好活跃啊,每个学员都是争先恐...
    蝶恋花_a892阅读 117评论 0 1