RocketMQ源码学习 (十五) 同步落盘原理和实现

1 引文

在CommitLog中,有mappedFileQueue属性,该queue中最后一个mappedFile是当前正在顺序写的对象;刷盘服务flushCommitLogService为CommitLog另一个属性,包含同步罗盘和异步罗盘。
异步落盘的逻辑为在FlushRealTimeService服务中的run方法里有个死循环,跳出条件为stopped == true,具体流程如下:
1.读取配置中的刷新间隔时长,线程休息指定时间
2.获取配置中的最少刷盘页数,默认是4页,只有脏数据达到"指定”页数后,才真正刷盘。
3获取强制刷盘周期,默认是10秒,达到强制刷盘周期后,一定会刷盘,不再考虑脏页大小
4.调用外部类CommitLog.mappedFileQueue.flush(…)进行刷盘。注意传递的参数:int flushPhysicQueueLeastPages;(当达到强刷周期后该值为0,没有则是4,即默认的4页)
在死循环结束后,会尝试10次刷盘,直到无数据被落盘后结束。
CommitLog.mappedFileQueue.flush(…)会调用mappedByteBuffer.force(),该方法是系统调用,将没有落盘的数据落盘。
异步刷盘不需要等到全部落盘后再返回,只要唤醒FlushRealTimeService服务线程就可以了。简单介绍完异步落盘后开始介绍今天的主角:同步落盘。

2 同步落盘

同步落盘中,调用存储消息的线程必须要等到asyncPutMessage(msg)方法消息存储到磁盘后才能返回,当生产者线程调用该方法后并不是亲力亲为自己将消息落盘,而是在GroupCommitService类中的线程去完成的,下图展示了两者在存储消息上的区别。其中,1~7步为将消息存储到MappedFile中的逻辑;构建请求的GroupCommitRequest实例中nextOffset表示存储完消息后下一条消息开始的offset,flushOKFuture.get()方法会阻塞线程,生产者线程将其创建完毕之后会调用GroupCommitService的putRequest方法加入到GroupCommitService中的List<GroupCommitRequest> requestsWrite属性中。get方法什么时候会被唤醒呢?1.超时;2.有结果返回后。

在这里插入图片描述
GroupCommitService继承自ServiceThread,有自己的线程,putRequest方法有两个作用:

  1. 将request添加到requestsWrite列表;
  2. 唤醒刷盘服务。
    线程的run方法的流程如下:
    在这里插入图片描述
    waitForRunning方法继承自ServiceThread,并在GroupCommitService中重写了onWaitEnd方法,waitForRunning如下:
    在这里插入图片描述
    GroupCommitService中的onWaitEnd方法调用了swapRequests()方法,该方法的作用为交换requestsWrite和requestsRead。为什么要交换呢?因为requestsWrite还会有数据往里写,防止其受到影响。
    doCommit方法的逻辑如下:
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值