RocketMQ-消息存储(二)、内存映射机制

RocketMQ的存储文件

RocketMQ的存储文件包括CommitLog文件、ConsumerQueue文件和IndexFile文件。

  • CommitLog :消息存储文件,所有消息主题的消息都存储在 CommitLog 文件中。
    Commitlog 文件存储目录为${ROCKET_HOME }/ store/commitlog 目录,每一个文件默认lG,一个文件写满后再创建另外一个,以该文件中第一个偏移量为文件名,偏移量小于 20 位用0补齐
  • ConsumeQueue :消息消费队列,消息到达 CommitLog 文件后,将异步转发到消息 消费队列,供消息消费者消费
  • IndexFile :消息索引文件,主要存储消息 Key 与Offset 的对应关系
    RocketMQ使用MappedFile、MappedFilQueue来封装存储文件。MappedFileQueue 可以 看作是${ROCKET_HOME }/store/commitlog 文件夹,而 MappedFile 则对应该文件夹下一个个的文件。
    RocketMQ 通过使用内存映射文件来提高 IO 访问性能,无论是 CommitLog ConsumeQueue还是IndexFile ,单个文件都被设计为固定长度,如果一个文件写满以后再创建一个新文件,文件名就为该文件第一条消息对应的全局物理偏移量。

MappedFileQueue映射文件队列

MappedFileQueue是MappedFile的管理容器,MappedFileQueue是对存储目录的封装,该目录下回存在多个内存映射文件(mappedFile)。在这里插入图片描述

  • storePath:存储目录
  • mappedFileSize:单个文件的存储大小
  • mappedFiles:MappedFile文件集合
  • allocateMappedFileService:创建MappedFile服务类
  • flushedWhere:当前刷盘指针,表示该指针之前的所有数据全部持久化到硬盘
  • committedWhere:当前数据提交指针,内存中byteBuffer当前的写指针,该值大于等于】flushedWhere

通过不同的维度来查找MappedFile

  • getMappedFileByTime:根据消息存储时间戳来查找MappedFile。从MappedFile列表中第一个文件开始查找,找到第一个最后一次更新时间大于待查找时间戳的文件,如果不存在,则返回最后一个MappedFile文件。
  • findMappedFileByOffset:根据消息偏移量offset查找MappedFile。由于使用了内存映射,只要存在于存储目录下的文件,都需要对应创建内存映射文件,如果不定时将已消费的消息从存储文件中删除,会造成极大的内存压力与资源浪费,所有RocketMQ采取定时删除存储文件的策略,也就是说在存储文件中,第一个文件不一定是00000000000000000000,因为该文件在某一时刻会被删除,故根据offset定位MappedFile的算法为(int)((offset/this.mappedFileSize)-(mappedFile.getFileFromOffset()/this.MappedFileSize))。
  • getMaxOffset:获取存储文件最大偏移量。返回MappedFile的getFileFormOffset()
  • getMinOffset:获取存储文件最小偏移量。返回最后一个MappedFile文件的fileFromOffset加上MappedFile文件当前的写指针。

MappedFile内存映射文件

  1. MappedFile初始化
    transientStorePoolEnable为true 表示内容先存储在堆外内存,然后通过 Commit 线程将数据提交到内存映射Buffer中,再通过 Flush 线程将内存映射 Buffer 中的数据持久化到磁盘中
  2. MappedFile提交(commit)
    内存映射文件的提交动作由 MappedFile的commit 方法实现:
    执行提交操作, commitLeastPages 为本次提交最小的页数,如果待提交数据不满 commitLeastPages ,则不执行本次提交操作,待下次提交。 writeBuffer 如果为空,直接返回 wrotePosition 指针 ,无须执行 commit 操作, 表明commit 操作主体是 writeBuffer.
    判断是否执行commit操作。如果文件已满返回true;如果commitLeastPages大于0,则比较 wrotePosition (当前 writeBuffe 的写指针)与上一次提交的指针(committedPosition) 的差值,除以 OS_ PAGE_ SIZE 得到当前脏页的数量,如果大于 commitLeastPages 则返回 true ;如果 commitLeastPages小于0 表示只要存在脏页就提交
  3. MappedFile刷盘(flush)
    刷盘是指将内存中数据刷写到磁盘,永久存储到磁盘中,其具体实现由mappedFile的flush方法实现:
    刷写磁盘,直接调用 mappedByteBuffer或者 fileChannel的 force 方法将内存中的数据持久化到磁盘,那么 flushedPosition 应该等于 MappedByteBuffer 中的写指针;如果 writeBuffer 不为空, 则flushedPosition 应等于上一次 commit 指针;因为上一次提交的数据就是进入到 MappedByteBuffer 中的数据;如 writeBuffer 空,数据是直接进入到 MappedByteBuffer, wrotePosition 代表的是 MappedByteBuffer 中的指针,故设置 flushedPosition 为wrotePosition。
  4. 获取MappedFile最大读指针(getReadPositon)
    RockketMQ文件的一个组织方式是内存映射方式,预先申请一块连续的固定大小的内存,需要一套指针标识当前最大有效数据 的位置。获取当前文件最大的可读指针。 如果 writeBuffer为空, 则直接返回当前的写指针;如果 writeBuffer 不为空, 则返回上一次提交的指针。在MappedFile 设计中,只有提交了的数 据(写入到 MappedByteBuffer FileChannel 中的数据 )才是安全的数据。
  5. MappedFile销毁
    关闭mappedFile,释放掉资源,并关闭文件通道,删除物理文件。

TransientStorePool

TransientStorePool:短暂的存储池。RocketMQ单独创建一个MappedByteBuffer内存缓存池,用来临时存储数据,数据先写入该内存映射中,然后由commit线程定时将数据从该内存复制到与目的物理文件对应的内存映射中。RokcetMQ引入该机制主要的原因是提供一种内存锁定,将当前堆外内存一直锁定在内存中,避免被进程将内存交换到磁盘。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值