broker的恢复过程

 

 

broker的启动恢复过程:
0.首先检查broker是正常关闭还是异常关闭的,如何判断这个broker是正常关闭还是异常关闭只需要判断store目录下的abort文件是否存在,如果是正常关闭的情况下,rocketmq注册了一个钩子函数,在jvm关闭的时候会去调用这个钩子函数,这个钩子函数会去删除abort这个文件,那么也就意味着如果是正常关闭这个文件应该是不存在的。

 


1.之后加载CommitLog文件到堆外内存当中,利用NIO技术中的MappedByteFile 文件内存映射。 创建CommitLog对象, CommitLog对象在初始化的过程中会初始化一个成员变量 MappedFileQueue,这个MappdFileQueue在整个broker的store目录下的文件的读写中起到了至关重要的地位,所有的文件读写操作都是在这个MappedFileQueue中完成的。读取所有Commitlog文件,
每一个CommitLog大小1G对应一个MappedFile,这个MappedFile就是存在MappedFileQueue当中的一个CopyOnWrite队列当中,将每一个MappedFile的WrotePoistion,CommitPoistion,FlushPoistion都设置为预先设置好的Mappfilesize大小(即1G),


2.然后再加载ConsumeQueue到堆外内存当中,加载的方式和加载CommitLog类似。 也是用MappedFileQueue去加载,底层还是利用了内存映射技术。


3.如果设置了索引服务的话,那么将索引文件也加载进来。


4.开始恢复文件调用 recover方法。 这个方法传进了一个参数lastExitOK,这个参数就是前面在判断是否正常关闭得到的一个boolean值, 在recover方法体中,首先第一件做的是恢复每个消息队列的真实物理偏移量。做法是这样的:
遍历所有的ConusmeQueue,每个ConsumeQueue中也存储了一个MappedFileQueue,综观整个broker的存储会发现, Commitlog,Consumequeue等都是利用MappedFileQueue封装的方法来操作文件的。  MappedFileQueue从倒数第三个文件开始校验队列文件,如果文件数量少于3个,那么从第一个开始弄。

20字节,20字节的读取判断,ConsumeQueue中的单个元素的构造是8字节的CommiltLogOffset(即CommitLog的物理偏移量),4字节的size(消息大小),8字节的tagsCode(tags值)。  会将这个三个依次读取并且判断,如果(offset>0&&size>0)说明没问题,继续读取下一个20字节判断。当一个MappedFile读取完毕后继续下一个MappedFile直到全部读取完成,如果size=0说明已经读取完毕。这边我们要注意到有个局部变量processOffset,这个变量的作用是拿来存储读取过程中MappedFile的最大偏移量,读到最后一个MappedFile结束后,processOffset的值也将会定格在最大的偏移量。然后将这个processOffset设置为MappedFileQueue的flushwhere,Commitedwhere,同时还要将队列中的脏数据通过truncateDirtyFiles方法过滤并删除。

 

 

当recoverConsumeQueue恢复完之后会根据lastExitOK的boolean值来执行commitLog的恢复,若是true执行正常的恢复,反之亦然。

 

来看看正常的情况,方法recoverNormally方法的逻辑:

这个方法的核心逻辑很简单,从commitlog中的第三个文件开始恢复(文件大于3个的情况,没到从第一个开始),将得到的文件从头开始解析读取并且校验,checkMessageAndReturnSize这个方法, 校验每一个元素,其中会判断魔数是否正确,判断每条消息中的bodyLen, topicLen, propertiesLength这三个的长度加起来是否等于totalLengh。成功则返回一个成功的dispathchRequest, 然后回到recoverNormally方法中,后面的逻辑类似于ConsumeQueue的恢复,判断size是否>0 大于0则代表恢复结束,然后最终设置好Flushwhere,Commitedwhere等参数。    最终还有个maxPhyOffsetConsumequeue>processOFFset的判断 这个判断在正常的关闭broker中只是为了保险起见加入的,实质上正常恢复是可以不用加的,这段代码在异常恢复的代码中也有在最后,当时却在那边有至关重要的地位。(后面分析)

 

如果是异常关掉broker则走的是recoverAbnormally逻辑代码太长了就不截取了,异常的逻辑和正常的相比不同点主要在于

它不是从倒数第三个开始恢复的而是从最大的那个commitlog 文件开始(即倒数第一个),找到第一个存储正常的文件,那么判断正不正常的依据是通过这几点,

1.一个是判断文件的魔数是否符合文件存储的规定MESSAGE_MAGIC_CODE(这是个常量),

2.判断文件中第一个消息的落盘时间storetimestamp是否等于0 等于0则直接返回false

3.对比文件第一条消息的时间戳与检测点(storecheckpoint这个就存在store目录下面),文件第一条消息的时间戳小于文件检测点说明该文件部分消息是可靠的,则从该文件开始恢复。文件检测点中保存了Commitlog文件、消息消费队列(ConsumeQueue)、索引文件(IndexFile)的文件刷盘点,RocketMQ默认选择这消息文件与消息消费队列这两个文件的时间刷盘点中最小值与消息文件第一消息的时间戳对比,如果messageIndexEnable为true,表示索引文件的刷盘时间点也参与计算。

根据这三点如果能找到符合的文件,则从这个文件开始验证恢复,这里要注意在验证恢复的同时还会转发消息到ConsumeQueue和索引文件(如果有开启), 所以这里就会存在重复消费的问题,当然rocketmq在设计上就没有去规避这个问题,需要我们自己在消费端做到幂等。(实际上应该是不会的,详细看我的另一篇文章broker异常恢复情况下 消息重复消费问题。

如果说都没找到符合的话,而Consumequeue中又有对应的逻辑队列,那么必须要删除掉。

刚才讲到正常恢复的逻辑中有个

异常中也有。 

实际上这代码的作用就是如果是异步刷盘的情况下,commitlog会转发消息给consumequeue,但是内容自身没有刷到conmmitlog上,然后机器宕机了就需要通过这个逻辑去重新对校一下。让consumequeue的最大物理偏移量和commitlog的最大物理偏移量对齐。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值