RocketMQ消息存储机制

目录

消息存储概述

CommitLog

ConsumeQueue

IndexFile

刷盘机制

源代码

同步刷盘

异步刷盘 


消息存储概述

RocketMQ默认的消息存储路径在/root/store/

生产者每次投递的消息都存储在commitLog文件里,再开启一个线程(ReputMessageService)异步的生成consumerQueue和indexFile

消费者根据queueOffset到conumerQueue找到对应消息的commitLogOffset,再到commitLog文件中找到具体的消息并返回

 

CommitLog

  1. 默认大小是1G
  2. 文件名是以起始偏移量命名
  3. 顺序写入,随机读写
  4. 被消费的消息不会立即删除,是以删除策略进行删除

ConsumeQueue

可以将ConsumeQueue理解为CommitLog的索引,因为CommitLog存储了所有topic的消息,通过引入ConsumeQueue来提高消息消费的速度。默认大小是48M,ConsumeQueue 存储的条目是固定大小,只会存储 8 字节的 commitlog 物理偏移量,4 字节的消息长度和 8 字节 Tag 的哈希值,固定 20 字节。

IndexFile

IndexFile就是索引文件,提供了一种可以通过key或时间区间来查询消息的方法

消息存储的核心代码主要在源码的CommitLog类中的putMessage方法,主要是干了将消息追加写入堆外内存中(对应方法mappedFile.appendMessage())和处理刷盘

刷盘机制

RocketMQ如果将消息只存在内存中的话,可靠性不高,虽然刷盘效率低但是可靠性高,并且保证断电后未删除的消息又能恢复使用。RocketMQ提供了两种写入方式,分别是同步刷盘和异步刷盘。

源代码

public void handleDiskFlush(AppendMessageResult result, PutMessageResult putMessageResult, MessageExt messageExt) {
    // Synchronization flush
    if (FlushDiskType.SYNC_FLUSH == this.defaultMessageStore.getMessageStoreConfig().getFlushDiskType()) {
        final GroupCommitService service = (GroupCommitService) this.flushCommitLogService;
        if (messageExt.isWaitStoreMsgOK()) {
            GroupCommitRequest request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes());
            service.putRequest(request);
            boolean flushOK = request.waitForFlush(this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout());
            if (!flushOK) {
                log.error("do groupcommit, wait for flush failed, topic: " + messageExt.getTopic() + " tags: " + messageExt.getTags()
                    + " client address: " + messageExt.getBornHostString());
                putMessageResult.setPutMessageStatus(PutMessageStatus.FLUSH_DISK_TIMEOUT);
            }
        } else {
            service.wakeup();
        }
    }
    // Asynchronous flush
    else {
        if (!this.defaultMessageStore.getMessageStoreConfig().isTransientStorePoolEnable()) {
            flushCommitLogService.wakeup();
        } else {
            commitLogService.wakeup();
        }
    }
}

同步刷盘

同步刷盘是等消息写到磁盘时才返回ack给Producer

优点:不会丢失数据,不会出现消息状态不一致的情况

缺点:性能低

流程:

  1. 将消息封装成GroupCommitRequest
  2. 将GroupCommitRequest放到List中,再唤醒GroupCommitService线程
  3. 循环将requestsRead刷到磁盘中
  4. 等待GroupCommitService线程将requestsRead刷完,超时则报错

异步刷盘 

异步刷盘是等消息写到堆外内存就返回ACK给Producer

优点:性能高

缺点:Master宕机或者磁盘损坏等情况会丢失少量数据

流程:

  1. 如果距离上次刷盘间隔10s,则直接刷盘
  2. 等待500ms刷一次,默认一次刷4页数据,如果超过10s则直接刷
  3. 刷完之后记录刷盘位置
  4. 最后冲洗之后再退出

如果将TransientStorePoolEnable设置为true,则会调用CommitRealTimeService线程来异步刷盘,该线程是用fileChannel.write将消息写入磁盘

流程:

  1. 每次至少刷4页数据
  2. 如果距离上次大于200ms则直接刷
  3. 最后冲洗之后再退出

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值