了解消息存储部分首先需要关注的几个方法,load()--Load previously stored messages、start()--Launch this message store、putMessage--Store a(or batch) message into store.
以及一些关键词:
  commitLog:      消息的物理存储相关
  consumeQueue:    逻辑队列存储相关
  IndexFile:           消息存储索引
  刷盘:             将写入内存的消息持久化
  主从同步(HAService):       Master中的数据同步到Slave中
  load()方法:         用于重启时,加载数据
load()方法用于重启时,加载数据,初始化boker时,boker中的initialize方法中会调用messageStore.load(),包括:commitLog.load()、 loadConsumeQueue()、 indexService.load、 recover(lastExitOK)
 
正文:
(一)消息存储开启基础服务 -- 在后台运行,时刻准备为存储服务
boker启动时,会初始化DefaultMessageStore,调用DefaultMessageStore.start()服务。
I. 初始化DefaultMessageStore时开启的服务
  预分配MapedFile对象服务(线程):AllocateMapedFileService
  分发消息索引服务(线程):   DispatchMessageService --(注:rockemq4.0版本中抛弃了该服务,对应变成了CommitLogDispatcherBuildConsumeQueue、CommitLogDispatcherBuildIndex内部类)
  消息索引服务(线程):     IndexService
II. DefaultMessageStore.start()会开启的服务(或服务线程)
  逻辑队列刷盘服务(线程):  FlushConsumeQueueService
  物理队列刷盘服务(线程):  FlushCommitLogService (该服务在初始化commitlog对象时开启)
  运行时数据统计服务(线程):    StoreStatsService
  从物理队列解析消息重新发送到逻辑队列服务(线程):ReputMessageService
  HA服务: HAService
  定时服务:ScheduleMessageService,如定时删除过期文件--cleanFilesPeriodically等。
(注:这些服务对象基本都在初始化DefaultMessageStore实例对象时被创建)
 
 
(二) 存储过程
rockemq4.0数据存储的过程与之前的版本存入过程与有很大的不同:
  如rocketmq 3.2.4中只有角色为SLAVE的boker会开启ReputMessageService服务。
  如rockemq4.0中将之前版本中废除了处理分发消息索引服务DispatchMessageService服务,更改为这两个类CommitLogDispatcherBuildConsumeQueue、CommitLogDispatcherBuildIndex。
  如rocketmq 3.2.4可以通过是否开启消息索引功能可以控制是否执行 Index索引。
 
2.1 rocketmq 3.2.4版本的数据存入过程:
I. commitLog数据存入
  • 如果boker角色为MASTER
  生产者每写入一条数据,boker端接受到消息后,DefaultMessageStore.putMessage调用Commit.putMessage方法,PutMessage首先要检查一些条件,比如:
    1. 每条数据第一写入的broker的属性必须为master,否则回返回PutMessageStatus.SERVICE_NOT_AVAILABLE状态,“message store is slave mode, so putMessage is forbidden ”. 
    2. 这条msg是否具有被写入的权限,否则回返回PutMessageStatus.SERVICE_NOT_AVAILABLE状态,"message store is not writeable, so putMessage is forbidden ".
    3. message topic长度校验
    4. message properties长度校验
  Commit.putMessage 首先将数据写入到commitlog对应的mapedFile中,每写入一条消息,通过mapedFile.appendMessage追加到MapedFile文件中,当MapedFile写满后,生成一个新的MapedFile,然后向这个MapedFile中追加消息,如此不断 ... ...,这些MapedFile装在MapedFileQueue中。
  commitLog中每向mapedFile中写入一个消息后,会返回一个AppendMessageResult对象,根据AppendMessageResult与msg消息信息,生成一个DispatchRequest对象,调用commit的内部类DispatchMessageService.putRequest(dispatchRequest)方法,将写入的消息对应dispatchRequest写入到定义的List<DispatchRequest> requestsWrite列表中。
  • 如果boker角色为SLAVE
  没有putMessage过程,数据加载通过HAService进行主从同步,同步MASTER中的逻辑队列,向commitLog存入数据。(过程比较复杂,有机会以后单独成文分析)
II. consumeQueue数据存入(indexFile数据存入可选)
  • 如果boker角色为MASTER
DispatchMessageService线程在后台一直运行,不断执行doDispatch()
while (!this.isStoped()) {
  try {
    this.waitForRunning(0);
    this.doDispatch();
  } catch (Exception e) {
    DefaultMessageStore.log.warn(this.getServiceName() + " service has exception. ", e);
  }
}
doDispatch()会将requestsWrite列表中的dispatchRequest处理,将它们转换成consumeQueue单元结构对应数据,这些数据追加到consumerQueue对应的MapedFile中。然后添加到consumerQueue的MapedFileQueue中。如果开启了消息索引功能即:isMessageIndexEnable==true,则将requestsWrite列表中的dispatchRequest传给indexService服务,然后indexService将这些消息写入IndexFile中。
  • 如果boker角色为SLAVE
  由于生产者产生消息不会直接到SLAVE,因此在SLAVE不会执行putMessage逻辑,它主要靠ReputMessageService 服务线程,从物理队列(commitlog)解析消息重新发送到逻辑队列,大致过程为: 从物理队列解析数据,生成dispatchRequest,如果数据正常,则将dispatchRequest传入给DispatchMessageService的List<DispatchRequest> requestsWrite,之后DispatchMessageService处理dispatchRequest的过程与上文一样。
 
2.2. rocketmq 4.0 版本的数据存入过程
I. commitLog数据存入过程基本不变
  不同的是,commit.putMessage过程并不会根据AppendMessageResult与msg消息信息,生成一个DispatchRequest对象,该版本中DispatchRequest对象的生成过程放在了ReputMessageService中,通过ReputMessageService生成DispatchRequest对象。该版本中ReputMessageService服务线程不像rocketmq 3.2.4中那样只为boker角色为SLAVE单独开设。
II. consumeQueue与indexFile数据存入
  rocketmq4.0中此过程的核心服务是ReputMessageService,与之前版本不同的是在rocketmq4.0版本中,consumeQueue与indexFile数据存入的服务线程独立出来了,分别使用CommitLogDispatcherBuildConsumeQueue和CommitLogDispatcherBuildIndex类处理,初始化DefaultMessageStore时,将这两个类存放入dispatcherList列表中:
this.dispatcherList.addLast(new CommitLogDispatcherBuildConsumeQueue());
this.dispatcherList.addLast(new CommitLogDispatcherBuildIndex());
在ReputMessageService服务线程启开后,不断从commitLog中解析数据,生成dispatchRequest :
DispatchRequest dispatchRequest = DefaultMessageStore.this.commitLog.checkMessageAndReturnSize(result.getByteBuffer(), false, false);
 之后向dispatcherList中的所有分发器分发dispatcherList:
DefaultMessageStore.this.doDispatch(dispatchRequest);
即执行:
CommitLogDispatcherBuildConsumeQueue.doDispatch(dispatchRequest)生成consumeQueue数据
CommitLogDispatcherBuildIndex.doDispatch(dispatchRequest)生成IndexFile数据
 
 
(三) 数据写入内存小结
即:内存映射
生成commitLog数据的核心接口:
this.commitLog.putMessage(msg)
将数据写入到commitlog对应的MapedFiLe对象中。
生成consumeQueue数据的核心接口:
public void putMessagePositionInfo(DispatchRequest dispatchRequest) {
  ConsumeQueue cq = this.findConsumeQueue(dispatchRequest.getTopic(), dispatchRequest.getQueueId());
  cq.putMessagePositionInfoWrapper(dispatchRequest);
}
将数据写入到consumeQueue对应的MapedFiLe对象中。
生成IndexFile数据的核心接口:
DefaultMessageStore.this.indexService.buildIndex(request);
将数据写入到IndexFile对应的MapedFiLe对象中。
 
 
(四)  内存文件落地 -- 刷盘
上文介绍了数据如何写入到逻辑队列、物理队列、索引的MapedFiLe中,这里介绍如何将逻辑队列、物理队列内存数据持久化到磁盘(索引文件的写入可以在以后的文章中单独分析)。
 
逻辑队列、物理队列内存文件刷盘方式相同,它们生成的MapedFile文件会放在各自对应的MapedFileQueue对象中,通过刷盘的方式,将MapedFileQueue持久化到物理磁盘上。
初始化DefaultMessageStore的时候会开启: 逻辑队列刷盘服务线程--FlushConsumeQueueService、将ConsumeQueue.mapedFileQueues刷入磁盘;
初始化commitlog对象时开启:物理队列刷盘服务线程--FlushCommitLogService,将commitlog.mapedFileQueues刷入磁盘。
这两个线程会分别将MapedFileQueue持久化到物理磁盘上。
对于commitlog的刷盘策略:
if (FlushDiskType.SYNC_FLUSH == defaultMessageStore.getMessageStoreConfig().getFlushDiskType()) {
  this.flushCommitLogService = new GroupCommitService();
} else {
  this.flushCommitLogService = new FlushRealTimeService();
}
异步刷盘使用的是FlushRealTimeService,同步刷盘使用的是GroupCommitService
刷盘过程要涉及到MapedFile,MapedFile以及java NIO相关的知识如MappedByteBuffer、FileChannel,可以学到的到东西很多,具体的刷盘实现过程见(下一篇)。
 
 

rocketmq消息存储概述的更多相关文章

  1. RocketMQ消息存储

    转载:RocketMQ源码学习--消息存储篇 消息中间件—RocketMQ消息存储(一) RocketMQ高性能之底层存储设计 存储架构 RMQ存储架构 上图即为RocketMQ的消息存储整体架构,R ...

  2. RocketMQ之六:RocketMQ消息存储

    一.RocketMQ的消息存储基本介绍 先看一张图: 1.Commit log存储消息实体.顺序写,随机读.2.Message queue存储消息的偏移量.读消息先读message queue,根据偏 ...

  3. 一张图进阶 RocketMQ - 消息存储

    前言 三此君看了好几本书,看了很多遍源码整理的 一张图进阶 RocketMQ 图片,关于 RocketMQ 你只需要记住这张图!觉得不错的话,记得点赞关注哦. [重要]视频在 B 站同步更新,欢迎围观 ...

  4. RocketMQ 消息存储

    消息存储 主要的存储文件: 1.消息文件(commitLog) 2.消息消费队列文件(consumeQueue) 3.Hash索引文件(IndexFile) 4.检测点文件(checkpoint) 5 ...

  5. 再说rocketmq消息存储

    两篇精彩的文章: <RocketMQ源码 — 三. Producer消息发送过程> <RocketMQ源码解析:Message存储> rocketmq通过netty获取到消息请 ...

  6. 【RocketMQ源码分析】深入消息存储(1)

    最近在学习RocketMQ相关的东西,在学习之余沉淀几篇笔记. RocketMQ有很多值得关注的设计点,消息发送.消息消费.路由中心NameServer.消息过滤.消息存储.主从同步.事务消息等等. ...

  7. rocketMq和kafka的架构区别

    概述 其实一直想写一篇rocketMq和kafka在架构设计上的差别,但是一直有个问题没搞明白所以迟迟没动手,今天无意中听人点播了一下似乎明白了这个问题,所以就有了这篇对比. 这篇博文主要讲清楚kaf ...

  8. Apache RocketMQ分布式消息传递和流数据平台及大厂面试宝典v4.9.2

    概述 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 Apache RocketMQ官网地址 https://rocketmq.apache.org/ Latest rel ...

  9. rocketMq概念介绍

    rocketMq官网 http://rocketmq.apache.org/ rocketMq逻辑概念介绍 rocketMq逻辑图 备注:    改图片分享自李占卫的网上家园 说明: 在rocketM ...

随机推荐

  1. 【DUBBO】zookeeper在dubbo中作为注册中心的原理结构

    [一]原理图 [二]原理图解释 流程:1.服务提供者启动时向/dubbo/com.foo.BarService/providers目录下写入URL2.服务消费者启动时订阅/dubbo/com.foo. ...

  2. 洛谷 P3802 小魔女帕琪

    传送门 题目大意:7个东西,每个有ai个,只有选7次 把7个东西都选到了才行. 题解:7!排列数*每次选择的概率 代码: #include<iostream> #include<cs ...

  3. linux网络设备理解

    网络层次 linux网络设备驱动与字符设备和块设备有很大的不同. 1. 字符设备和块设备对应/dev下的一个设备文件.而网络设备不存在这样的设备文件.网络设备使用套接字socket访问,虽然也使用re ...

  4. maven打包报错:在类路径或引导类路径中找不到程序包 java.lang

    刚下了个新项目,跑了下maven报错了: E:\workspace\portalframe>mvn clean install [INFO] Scanning for projects... [ ...

  5. MIT App Inventor使用与入门教程

    前言:随着信息技术新课标的提出,移动app应用设计被加入到新课标,程序与算法得到体现,学生的创造性,计算思维与信息意识也可以在其中得到体现. 安卓app开发目前比较火热的是Eclipse和Androi ...

  6. Zookeeper--配置服务

    Zookeeper--配置服务 配置服务是分布式应用中重要的服务,作用是使集群中的机器可以共享配置信息中公共的部分.ZooKeeper可作为一个具有高可用,全局一致的配置服务器,允许客户端获取和更新配 ...

  7. 20165226 2017-2018-4 《Java程序设计》第7周学习总结

    20165226 2017-2018-4 <Java程序设计>第7周学习总结 教材学习内容总结 第十一章 JDBC与MySQL数据库 下载MySQL最新版本. 连接数据库 下载JDBC-M ...

  8. python学习 (三十五) logging

    1  demo import logging # log level: # DEBUG # INFO # Warning # Error # CRITICAL logging.basicConfig( ...

  9. 【洛谷】P1196 银河英雄传说(并查集)

    题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压顶 ...

  10. 浅谈PHP面向对象编程(五、继承)

    5.0 继承 5.1 继承的概念 在现实生活中,继承一般指的是子女继承父辈的财产.在程序中,继承描述的是事物之间的所属关系,通过继承可以使许多事物之间形成一种关系体系 . 例如猫和狗都属于动物,程序中 ...