TimerMessageStore 简略介绍

  • 延迟队列 rmq_sys_wheel_timer
  • 指定时间的延迟消息。会先投递到 rmq_sys_wheel_timer 队列中
  • 然后由 TimerMessageStore 消费队列数据,将数据消费到 timerWheel 使用时间轮算法,实现秒级任务

TimerMessageStore 操作的文件

  • store\consumequeue\rmq_sys_wheel_timer 从队列中读取消息, 提取数据存到 timerlogtimerwheel
  • store\checkpoint 对应 TimerMessageStore#timerCheckpoint
    • lastReadTimeMs 上次消费的时间节点
    • lastTimerLogFlushPos 最后刷新 log的 pos
    • lastTimerQueueOffset 最后一次消费的队列节点
    • masterTimerQueueOffset 主 Broker 的队列消费节点
  • store\timerwheel 时间轮,内由 Slot 组成 结构如下
    • timeMs 消息到达时间
    • firstPos 开始的 pos
    • lastPos 结束的 pos 在 timerLog 中读取数据, 后面会讲具体逻辑
    • num 消息数量
    • magic no use now, just keep it
  • store\timerlog 对应 TimerMessageStore#timerCheckpoint

    里边也是由多个 mappedFile 组成。

    主要是存储原msg的数据,

    因为从 rmq_sys_wheel_timer 消费了之后,

    会存到 timerwheeltimerlog

TimerMessageStore 启动

  • enqueueGetService.start();
  • enqueuePutService.start();
  • dequeueWarmService.start();
  • dequeueGetService.start();
  • timerFlushService.start();
  • dequeueGetMessageServices[getThreadNum].start();
  • dequeuePutMessageServices[getThreadNum].start();

深入 TimerMessageStore 之 TimerEnqueueGetService

  • TimerMessageStore.this.enqueue 默认 100毫秒执行一次
  • 从 消息队列 rmq_sys_wheel_timer 消费数据 ps: currQueueOffsetcheckpoint 读取出来的
  • 将消费出来的数据, 封装成 TimerRequest 投入到 enqueuePutQueue
  • currQueueOffset + 1 进入下一个循环 消费下一个 offset 节点

深入 TimerMessageStore 之 TimerEnqueuePutService

  • 消费 enqueuePutQueue 中的数据
  • shouldRunningDequeue && req.getDelayTime() < currWriteTimeMs 检查消费的消息是否已到达投递时间。
    • 到达时间。投递到 dequeuePutQueue.put(req);
    • 消息未到达时间 doEnqueue ->
      • timerWheel.getSlot(delayedTime) 获取延迟时间插槽。
      • 构建 ByteBuffer 投入 timerLog 中数据结构为:
      • |消息大小|前一个节点的pos|magic|log写入时间|延迟时间|offsetPy|sizePy|realTopic|0
      • timerLog.append 返回插入位置 ret
      • 构建 timerWheel |消息到达时间戳|firstPos|ret (timerLog.append返回位置)| 消息数量| 0|

深入 TimerMessageStore 之 TimerDequeueGetService

  • 消费 timerWheel 中的数据
  • 根据 currReadTimeMs 来获取 timerWheel 插槽数据
    • currReadTimeMs 初始化的时候 timerCheckpoint.getLastReadTimeMs() 读取的是上次最后消费的数据
    • 假设broker 宕机了一段时间。那么 currReadTimeMs 会按照上一次宕机的时间开始搜寻数据, 这样子宕机消息也不会丢失。会在启动的那段时间被投递出去
    • currReadTimeMsmoveReadTime 方法中会自增
  • timerWheel.getSlot(currReadTimeMs); 读取插槽数据
    • long currOffsetPy = slot.lastPos; 读取插槽属性, 最后一个pos节点
    • timerLog.getWholeBuffer(currOffsetPy) 根据 currOffsetPy 获取 SelectMappedBufferResult
    • timerLogSelectMappedBufferResult 中获取数据。
      • prevPos 上一个节点数据
      • enqueueTime 放入 timerLog 的时间
      • delayedTime 消息到达时间戳
      • offsetPy commitLog的数据位置
      • sizePy commitLog的数据大小
    • 构建 TimerRequest 讲消息投递到 dequeueGetQueue
    • currOffsetPy = prevPos 将位置移动到前一个,进行遍历

深入 TimerMessageStore 之 TimerDequeueGetMessageService

  • 默认有三个 TimerDequeueGetMessageService 实例同时消费 dequeueGetQueue
  • getMessageByCommitOffsetcommitLog 中读取原投递的消息数据
  • 读取 uniqkey 判断不在 deleteList 中的时候 将消息投递到 dequeuePutQueue 中去

深入 TimerMessageStore 之 TimerDequeuePutMessageService

  • 默认有三个 TimerDequeuePutMessageService 实例同时消费 dequeuePutQueue
  • convert(tr.getMsg(), tr.getEnqueueTime(), needRoll(tr.getMagic())); 将消息转换成原始的 topic 消息,清除无用属性
  • doPut -> messageStore.putMessage(message) 将消息投递到指定 messageQueue

TimerFlushService

  • timerLog 刷盘
  • timerWheel 刷盘
  • timerCheckpoint 刷盘

TimerMessageStore 初始化加载源码

  • timerLog.load() 加载文件
  • timerMetrics.load 加载文件
  • recover ->
    • recoverAndRevise(lastFlushPos, true) ps: (用于 timerWheltimerLog 的数据保持一致刷新)

      • lastFlushPos 最后一次刷盘的位置, 其实最终是拿到 timerlog -> mappedFile 的第几个文件
      • 遍历这个 mappedFile 的数据
      • timerWheel.reviseSlot 修改插槽数据。 检查这个时间的插槽是否已经有填充数据。
        • 如果有的话,刷新 lastPos (顺序遍历。这里最终还是会是最后一个 lastPos)
        • 如果不存在插槽数据 则插入插槽数据 putSlot
    • reviseQueueOffset(processOffset); 读取 timerLog 最后一个数据, 为了校验最后一个数据是否正常,是否能读取到消息。
    • 确认 currQueueOffset 数据
    • 确认 currReadTimeMs 数据

RocketMq5.0 任意延迟时间 TimerMessageStore 源码解析的更多相关文章

  1. abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析

    老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...

  2. EventBus3.0源码解析

    本文主要介绍EventBus3.0的源码 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递. EventBus使用简单,并将事件发布和订阅充 ...

  3. solr&lucene3.6.0源码解析(四)

    本文要描述的是solr的查询插件,该查询插件目的用于生成Lucene的查询Query,类似于查询条件表达式,与solr查询插件相关UML类图如下: 如果我们强行将上面的类图纳入某种设计模式语言的话,本 ...

  4. solr&lucene3.6.0源码解析(三)

    solr索引操作(包括新增 更新 删除 提交 合并等)相关UML图如下 从上面的类图我们可以发现,其中体现了工厂方法模式及责任链模式的运用 UpdateRequestProcessor相当于责任链模式 ...

  5. Heritrix 3.1.0 源码解析(三十七)

    今天有兴趣重新看了一下heritrix3.1.0系统里面的线程池源码,heritrix系统没有采用java的cocurrency包里面的并发框架,而是采用了线程组ThreadGroup类来实现线程池的 ...

  6. Masonry1.0.2 源码解析

    在了解Masonry框架之前,有必要先了解一下自动布局的概念.在iOS6之前,UI布局的方式是通过frame属性和Autoresizing来完成的,而在iOS6之后,苹果公司推出了AutoLayout ...

  7. Retrofit2.0源码解析

    欢迎访问我的个人博客 ,原文链接:http://wensibo.net/2017/09/05/retrofit/ ,未经允许不得转载! 今天是九月的第四天了,学校也正式开学,趁着大学最后一年的这大好时 ...

  8. 04、NetCore2.0下Web应用之Startup源码解析

    04.NetCore2.0Web应用之Startup源码解析   通过分析Asp.Net Core 2.0的Startup部分源码,来理解插件框架的运行机制,以及掌握Startup注册的最优姿势. - ...

  9. Android事件总线(二)EventBus3.0源码解析

    1.构造函数 当我们要调用EventBus的功能时,比如注册或者发送事件,总会调用EventBus.getDefault()来获取EventBus实例: public static EventBus ...

  10. 简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析

    简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析 虽然经常用 OAuth 2.0,但是原理却不曾了解,印象里觉得很简单,请求跳来跳去,今天看完相关介绍,就来捋一捋 ...

随机推荐

  1. 补五月五号java基础知识点

    1.容器类:容器类是java以类库的形式供有用户开发程序时可直接使用的各种数据结构.2.java容器框架中有两个名称分别为Collection和Set的接口,为防止名称的冲突,本书将Collectio ...

  2. 添加索引后SQL消耗量在执行计划中的变化

    不同索引的执行效率也是不一样的,下面比较三条SQL语句在正常查询与建立普通索引与位图索引后的CPU消耗量的变化,目的为了是加强对索引的理解与运用 实验步骤:1.创建有特点的大数据表.为了保证索引产生前 ...

  3. Mybatis-Plus如何自定义SQL注入器?

    有关Mybatis-Plus常用功能之前有做过一篇总结: MyBatisPlus常用功能总结!(附项目示例) 一.什么是SQL注入器 我们在使用Mybatis-Plus时,dao层都会去继承BaseM ...

  4. 基于Python的爬虫案例

    案例1:使用爬虫爬取京东华为手机用户评论 本案例借鉴哔哩哔哩博客主视频教程,感谢其教程为我开启了爬虫之旅:https://www.bilibili.com/video/BV1Yt4y1Y7nt?t=3 ...

  5. JavaScript 发布-订阅设计模式实现 React EventBus(相当于vue的$Bus)非父子之间通信

    提前声明: 我没有对传入的参数进行及时判断而规避错误,仅仅对核心方法进行了实现: 解决了react的非父子间的通信: 参考文档:https://github1s.com/browserify/even ...

  6. DRF的filter组件

    DRF的Filter组件 如果某个API需要传递一些条件进行搜索,其实就在是URL后面通过GET传参即可,例如: /api/users?age=19&category=12 在drf中filt ...

  7. 【深入浅出Spring原理及实战】「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常

    学习Spring源码的建议 阅读Spring官方文档,了解Spring框架的基本概念和使用方法. 下载Spring源码,可以从官网或者GitHub上获取. 阅读Spring源码的入口类,了解Sprin ...

  8. vite不能选配方案?vite-creater强势来袭!

    我正在参加「掘金·启航计划」 项目背景 vite出现之后,迅速带走了一大波webpack的使用者,即使是对打包工具不熟悉的小白,也能很快感受到两者的区别--vite快的多! vite官方文档第一句也是 ...

  9. 玩一玩 Ubuntu 下的 VSCode 编程

    一:背景 1. 讲故事 今天是五一的最后一天,想着长期都在 Windows 平台上做开发,准备今天换到 Ubuntu 系统上体验下,主要是想学习下 AT&T 风格的汇编,这里 Visual S ...

  10. Mysql列转行, group_concat的使用

    开始业务的查询的时候碰到一个sql的查询语句问题,主要是 group_concat 之前没用过,现在记录一下怎么用 group_concat 用法, 可以将相同的行组合起来 group_concat( ...