美文网首页RocketMQ系列
RocketMQ系列(五):消息存储

RocketMQ系列(五):消息存储

作者: 范柏柏 | 来源:发表于2020-06-07 15:53 被阅读0次

    都存什么

    • commitLog文件
    • consumeQueue文件
    • indexFile文件
    • 报错文件等等

    存在哪

    存在每个broker的磁盘中

    commitLog文件

    是什么?

    消息真正存储的地方。消息发送到broker的时候。先存储到commitLog,broker存储到commitLog后就通知producer消息发送成功了。commitLog到consmeQueue是broker的分发策略去做的。

    存储结构

    存在 rocketmq/store/commitlog文件夹中。
    以offset为文件名,存储message。
    每个文件默认都是1G。一个文件写满后,创建另外一个文件,以该文件的第一个message的偏移量命名。文件名20位,不够补0。


    存储结构.png

    因为。message的大小(长度)是固定的,所以可以通过offset快速找到文件,再通过长度快速找到这条消息。这里和数组很像,存数组头的地址信息,后面寻址,直接用数组头+偏移量直接就能找到。

    commitLog不是永久落盘的。默认存活时间是72小时,超过72小时,就标记为失效文件,默认每天凌晨4点清除失效文件。

    是直接落盘么

    肯定不是啊。中间有一层buffer(NIO内存映射问文件)


    内存映射文件.png

    MapperFileQueue相当于commitlog这个文件夹
    MapperFile相当于commitlog文件夹下的每个文件

    消息发送到后,先存在这个内存变量中,根据刷磁盘策略,往磁盘中刷数据。也就是刷脏页。
    刷脏页策略:

    • 同步:写入buffer,马上刷脏页,然后再返回producer消息发送成功。这样,能防止发送阶段消息不丢失。
    • 异步:写入buffer,就返回producer消息发送成功。然后根据broker的刷脏页策略来刷脏页。

    异步刷脏页策略

    rocketMq有两个参数去控制

    vm.dirty_background_bytes = 0
    vm.dirty_background_ratio = 10
    vm.dirty_bytes = 0
    vm.dirty_expire_centisecs = 3000
    vm.dirty_ratio = 30
    vm.dirty_writeback_centisecs = 500

    vm.dirty_background_ratio = 10
    当脏页数量达到系统内存10%时就会触发pdflush/flush/kdmflush等后台进程,将一部分缓存的脏页异步的刷进磁盘。
    vm.dirty_ratio = 30
    当脏页数量达到系统内存30%时,系统开始同步的将脏页刷入磁盘,同时会阻塞其他进程的写操作。

    10/30是系统默认值,可以自己根据业务情况设置。

    写的过程是什么

    因为存在一个地方(commitLog),所以消息必须要顺序写。每次写请求进入后,先拿写锁,阻塞顺序写。

    consumeQueue文件

    是什么

    这个是真正的mq的队列。里面不存具体的消息,而是存消息的指针。这个指针指向commitlog中该消息的位置。
    这样做的好处是:
    1、扩展性好。消息的真是数据存在一个地方,不会根据queue的变动而变动。
    2、查询速度快。

    存储结构

    存储结构.png

    第一层是topic。
    第二层是topic下queue队列id。
    第三层是队列下的消息文件。

    单个ConsumerQueue文件中默认包含30万个条目,单个文件的长度为30W * 20字节。


    ConsumerQueue文件.png

    commitlog在向consumerQueue转发的时候,会根据producer中的send策略,判断转发到哪个队列中。
    策略包括:轮训、随机、key hash。

    怎么查找

    consumeQueue可以理解为写队列。
    针对于查找还会有一个读队列processQueue。
    每个消费者group,都会有隔离的一组队列,通过processQueue做到的每个group的隔离。
    消费者根据 offset和tag拉consumerQueue的数据 到 processQueue,最终消费的是processQueue。processQueue是每个组隔离的。

    indexFile索引文件

    是什么

    是commitLog的索引文件。与queue队列无关。单纯的commitLog以key为索引的索引文件。


    indexFile索引文件.png

    slot table存的是key的hash值。也就是后面index的索引。有hash冲突怎么办,这里就不是链表法了,用的是二次hash来解决hash冲突。
    index linked list: 存的是具体的索引。

    index linked list: 存的是具体的索引。


    具体索引.png

    key hash: message key的hash值
    phyOffset: message在commitlog的物理文件地址,可以直接查询到该消息(存储的核心机制)
    timeDiff:message的落盘时间与header里的beginTimestamp的差值(为了节省存储空间,如果直接存message的落盘时间就得8bytes)
    prevIndex: hash冲突处理的关键之处,相同hash值上一个消息索引的index(如果当前消息索引是该hash值的第一个索引,则prevIndex=0, 也是消息索引查找时的停止条件。)

    相关文章

      网友评论

        本文标题:RocketMQ系列(五):消息存储

        本文链接:https://www.haomeiwen.com/subject/qwqctktx.html