RocketMQ 源码分析 05 消息存储

RocketMQ引入了ConsumeQueue,每个消息主题包括多个消息消费队列,每个消息队列有一个消息文件 

Broker 接收到生产者发送消息请求后如何存储在 Broker 上

 核心实现类DefaultMessageStore

先看核心方法putMessage

1.校验不能是slave,只允许写master

2.校验message store是可写的

3.校验mq的topic长度不能超过最大限制256

4.校验mq属性不能过长

5.检测操作系统页写入是否繁忙

6.将日志写入CommitLog 文件,具体实现类 CommitLog

   6.1 需要加锁putMessageLock

   6.2 设置消息存储时间

   6.3 把消息追加到mappedFile:先获取mappedFile的位移createOffset,然后根据写入数据大小构建出mappedFileLast

        然后调用appendMessage 追加到文件;

        this.wrotePosition.addAndGet(result.getWroteBytes());  写完后更新wrotePosition

7.创建消息id

8.记录消费队列consumeQueue 信息

9.把message序列化成为字节数组

10.检查当前消息长度是否超过最大限制

11.写入到msgStoreItemMemory,也就是把消息存入到内存中

12. 重点讲解一下AppendMessageResult方法。

消息刷盘的实现,分成同步刷盘,异步刷盘

1.同步刷盘实现

 

  1.1 构建一个GroupCommitRequest

  1.2 等待同步刷盘任务完成,如果超时,则返回刷盘错误;正常就返回给调用方

从上面的代码看,我们可以把 doCommit 方法当成业务方法,在 run 方法的循环被调用,每执行完一次 doCommit 等待10毫秒,这也是 waitForRunning 的核心逻辑,doCommit 中的任务是通过调用如下方法:

10ms执行一次提交doCommit

刷盘具体实现:MappedFileQueue。

1. 根据上次刷新的位置,得到当前的 MappedFile 对象。

2. 执行 MappedFile 的 flush 方法。

3.更新上次刷新的位置。

刷写的实现逻辑就是调用 FileChannel 或 MappedByteBuffer 的force 方法

根据上次刷盘偏移量,找到当前待刷盘mappedFile对象

 request.waitForFlush, 类似于 Future 模式,在这方法里进行阻塞等待。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

异步刷盘

2.2 异步刷盘

异步刷盘机制,实现原理很简单,就是按照配置的周期定时提交信息到 MappedFile,定时刷写到磁盘,我们重点关注如下几个配置项。

1)消息追加,也就是将消息追加到 CommitLog 文件对应的内存映射区(本过程是加锁的,非并发;2)刷盘阶段(并发)就是将内存区数据刷写到磁盘文件(支持同步、异步刷盘);3)主从同步处理(并发)。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

RocketMQ的刷盘机制就介绍到这,我们再简单做个总结。

先讲一下 RocketMQ 的存储设计亮点:(以CommitLog为例)。

单个 commitlog 文件,默认大小为 1G,由多个 commitlog 文件来存储所有的消息,commitlog 文件的命名以该文件在整个commitlog中的偏移量来命名,举例如下。

例如一个 commitlog 文件,1024个字节。

第一个文件: 00000000000000000000

第二个文件: 00000000000000001024

MappedFile 封装一个一个的 CommitLog 文件,而 MappedFileQueue 就是封装的就是一个逻辑的 commitlog 文件。mappedFile队列,从小到大排列。

使用内存映射机制,MappedByteBuffer, 具体封装类为MappedFile。

1、同步刷盘每次发送消息,消息都直接存储在 MapFile 的 mappdByteBuffer,然后直接调用 force() 方法刷写到磁盘,等到 force 刷盘成功后,再返回给调用方(GroupCommitRequest#waitForFlush)就是其同步调用的实现。

2、异步刷盘

分为两种情况,是否开启堆外内存缓存池,具体配置参数:MessageStoreConfig#transientStorePoolEnable。

1)transientStorePoolEnable = true 

消息在追加时,先放入到 writeBuffer 中,然后定时 commit 到 FileChannel,然后定时flush

2)transientStorePoolEnable=false(默认),不开启堆外内存,就存入到MappedByteBuffer

消息追加时,直接存入 MappedByteBuffer(pageCache) 中,然后定时 flush。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

存储文件组织与内存映射

RocketMQ使用MappedFile, MappedFileQueue来封装存储文件

1.根据消息存储时间戳查找MappedFile :

    从MappedFile列表中第一个文件开始查找,找到第一个最后一次更新时间戳大于待查找时间戳的文件。不存在就返回最后一个MappedFile文件

2.根据消息偏移量offset查找MappedFile :

   

 

4.5.2 ConsumeQueue

1.提供根据消息存储时间 查找具体实现的方法 getOffsetInQueueByTime

   根据时间戳定位到物理文件,然后根据二分查找来加速检索

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值