重新理解 RocketMQ Commit Log 存储协议
最近突然感觉:很多软件、硬件在设计上是有 root reason 的,不是 by desgin 如此,而是解决了那时、那个场景的那个需求。一旦了解后,就会感觉在和设计者对话,了解他们的思路,学习他们的方法,思维同屏:活到老学到老。
问题思考
1、Consumer Queue Offset 是连续的吗, 为什么?
2、Commit Log Offset 是连续的吗, 为什么?
3、Java 写的文件,默认是大端序还是小端序,为什么?
Commit Log 真实分布
在大家思考之际, 我们回想下 commit log 是怎么分布的呢?
在 Broker 配置的存储根目录下,通过查看 Broker 实际生成的 commit log 文件可以看到类似下面的数据文件分布:
可以看到,真实的存储文件有多个, 每一个都是以一串类似数字的字符串作为文件名的,并且大小 1G。
我们结合源码可以知道,实际的抽象模型如下:
由上图得知:
Commit Log 是一类文件的称呼,实际上 Commit Log 文件有很多个, 每一个都可以称为 Commit Log 文件。如图中表示了总共有 T 个 Commit Log 文件,他们按照由过去到现在的创建时间排列。
每个 Commit Log 文件都保存消息, 并且是按照消息的写入顺序保存的,并且总是在写创建时间最大的文件,并且同一个时刻只能有一个线程在写。如图中第 1 个文件,1,2,3,4... 表示这个文件的第几个消息,可以看到第 1234 个消息是第 1 个 Commit Log 文件的最后一个消息,第 1235 个消息是第 2 个 Commit Log 的第 1 个消息。
说明 1:每个 Commit Log 文件里的全部消息实际占用的存储空间大小 <=1G。这个问题大家自行思考下原因。
说明 2:每次写 Commit Log 时, RocketMQ 都会加锁,代码片段见 https://github.com/apache/rocketmq/blob/7676cd9366a3297925deabcf27bb590e34648645/store/src/main/java/org/apache/rocketmq/store/CommitLog.java#L676-L722
我们看到 Commit Log 文件中有很多个消息,按照既定的协议存储的,那具体协议是什么呢, 你是怎么知道的呢?
Commit Log 存储协议
关于 Commit Log 存储协议,我们问了下 ChatGPT, 它是这么回复我的,虽然不对,但是这个回复格式和说明已经非常接近答案了。
我们翻看源码,具体说明下:https://github.com/apache/rocketmq/blob/rocketmq-all-4.9.3/store/src/main/java/org/apache/rocketmq/store/CommitLog.java#L1547-L1587
我整理后, 如下图:
说明 1:我整理后的消息协议编号和代码中不是一致的,代码中只是标明了顺序, 真实物理文件中的存储协议会更详细。说明 2:在我写的《RocketMQ 分布式消息中间件:核心原理与最佳实践》中,这个图缺少了 Body 内容,这里加了,也更详细的补充了其他数据。 这里有几个问题需要说明下:
1、二进制协议存在字节序,也就是常说的大端、小端。大小端这里不详细说明感兴趣的同学自己 google 或者问题 ChatGPT,回答肯定比我说的好。
2、在 java 中, 一个 byte 占用 1 个字节,1 个 int 占用 4 个字节,1 个 short 占用 2 个字节,1 个 long 占用 8 个字节。
3、Host 的编码并不是简单的把 IP:Port 作为字符串直接转化为 byte 数组,而是每个数字当作 byte 依次编码。在下一节的 Golang 代码中会说明。
4、扩展信息的编码中,使用了不可见字符作为分割,所以扩展字段 key-value 中不能包含那 2 个不可见字符。具体是哪 2 个,大家找找?
我们看到这个协议后,如何证明你的物理文件就是按照这个协议写的呢?
用 Golang 解开 RocketMQ Commit Log
RocketMQ 是用 java 写的,根据上文描述的存储协议,我用 Golang 编写了一个工具,可以解开 Commit Log 和 Cosumer Queue,代码地址:https://github.com/rmq-plus-plus/rocketmq-decoder。
这个工具目前支持 2 个功能:
1、指定 Commit Log 位点,直接解析 Commit Log 中的消息,并且打印。
2、指定消费位点,先解析 Consumer Queue,得到 Commit Log Offset 后,再根据 Commit Log Offset 直接解析 Commit Log,并且打印。
在 Golang 中没有依赖 RocketMQ 的任何代码,纯粹是依靠协议解码。
这里贴了一段 golang 中解析 Commit Log Offset 的例子:在 java 中这个 offset 是一个 long 类型,占用 8 个字节。
在 golang 中,读取 8 个字节长度的数据,并且按照大端序解码为 int64,就可以得到正常的 Commit Log Offset。
我跑了一个 demo 结果,大家参考:
回答最初的问题
以下为个人见解,大家参考:
1、Consumer Queue Offset 是连续的吗, 为什么?
是连续的。
consumer queue offset,是指每个 queue 中索引消息的下标,下标当然是连续的。消费者也是利用了这个连续性,避免消费位点提交空洞的。
每个索引消息占用相同空间,都是 20 字节,结构如下:
这里物理位点也就是 Commit Log Offset。
2、Commit Log Offset 是连续的吗, 为什么?
不是连续的。
Commit Log Offset 是指的每个消息在全部 Commit Log 文件中的字节偏移量, 每个消息的大小是不确定的,所以 Commit Log Offset,也即是字节偏移量肯定是不一样的。
并且可以知道,每两个偏移量的差的绝对值就是前一个消息的消息字节数总长度。
并且上文中图 “Commit Log 存储文件分布抽象” 中的有误解,每个小方格的大小其实是不一样的。
3、Java 写的文件,默认是大端序还是小端序,为什么?
大端序。大端序其实有字节存储顺序和网络传输顺序,java 中默认用的大端序,保持和网络传输一样,这样方便编解码。
每段网络传输层的数据报文最前面的字节是表达后面的数据是用什么协议传输的,这样数据接收者在接受数据时, 按照字节顺序,先解析协议,再根据协议解码后面的字节序列,符合人类思考和解决问题的方式。
讨论说明:由于 RocketMQ 一些版本可能有差异,本文在 4.9.3 版本下讨论,大家可以参考这个方法,解开
5.0 甚至其他版本,其他数据文件的存储协议格式。
相关文章:

重新理解 RocketMQ Commit Log 存储协议
最近突然感觉:很多软件、硬件在设计上是有 root reason 的,不是 by desgin 如此,而是解决了那时、那个场景的那个需求。一旦了解后,就会感觉在和设计者对话,了解他们的思路,学习他们的方法,思维…...

ES6基础知识十:你是怎么理解ES6中 Decorator 的?使用场景?
一、介绍 Decorator,即装饰器,从名字上很容易让我们联想到装饰者模式 简单来讲,装饰者模式就是一种在不改变原类和使用继承的情况下,动态地扩展对象功能的设计理论。 ES6中Decorator功能亦如此,其本质也不是什么高大…...

接口/Web自动化测试如何做?框架如何搭建封装?
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 自动化测试怎么做…...
Linux怎么从网络上下载文件
wget命令用于从网络上下载文件 下载文件: wget [URL]使用wget命令加上要下载的文件的URL,可以将文件下载到当前目录。 指定保存的文件名: wget -O [保存的文件名] [URL]使用-O选项后跟保存的文件名,可以指定下载的文件保存的名称…...
Flutter携带JSON参数post请求
在Flutter中发送带有JSON参数的网络请求,你可以使用HTTP库(如http或dio)来实现。以下是使用http库发送网络请求并携带JSON参数的示例: import package:http/http.dart as http; import dart:convert;// 创建参数Map Map<Strin…...

【vue】vue-image-lazy图片懒加载使用与介绍【超详细+npm包源代码】
简介 当前插件是基于vue3,写的一个图片懒加载,文章最下方是npm包的源码,你可以自己拿去研究和修改,如有更好的想法可以留言,如果对你有帮助,可以点赞收藏和关注,谢谢。 后续会添加图片放大和切…...

MFC第二十四天 使用GDI对象画笔和画刷来开发控件(分页控件选择态的算法分析、使用CToolTipCtrl开发动静态提示)
文章目录 GDI对象画笔和画刷来开发控件梯形边框的按钮控件CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp 矩形边框的三态按钮控件 CToolTipCtrl开发动静态提示CMainDlg.hCMainDlg.cppCLadderCtrl.hCLadderCtrl.cpp: 实现文件 矩形边框的三态按钮控件 CToolTipCtrl开发动…...

【NLP-新工具】语音转文本与OpenAI的用途
一、说明 OpenAI最近2022发布了一个名为Whisper的新语音识别模型。与DALLE-2和GPT-3不同,Whisper是一个免费的开源模型。它的主要功能就是将语音翻译成文本。本文将介绍如何使用这个重要应用库。 二、 Whisper概念 2.1 Whisper是啥? Whisper 是一种自动…...
try-catch-finally的字节码原理
Java 中有一个非常重要的内容是 try-catch-finally 的执行顺序和返回值问题,其中 finally 一定会执行,但是为什么会这样? 下面看下 try-catch-finally 背后的实现原理 try-catch public class Test {public static void main(String[] args)…...

基于双层优化的微电网系统规划设计方法(Matlab代码实现)
目录 💥1 概述 1.1 微电网系统结构 1.2 微电网系统双层规划设计结构 1.3 双层优化模型 1.4 上层容量优化模型 1.5 下层调度优化模型 📚2 运行结果 🎉3 文献来源 🌈4 Matlab代码、数据、文章讲解 💥1 概述 文献来源&…...

【Nginx13】Nginx学习:HTTP核心模块(十)Types、AIO及其它配置
Nginx学习:HTTP核心模块(十)Types、AIO及其它配置 今天学习的内容也比较简单,主要的是 Types 相关的配置,另外还会了解一下 AIO 以及部分没有特别大的分类归属的配置指令的使用。后面的内容都是 HTTP 核心模块中比较小…...
2023年华数杯数学建模C题思路分析
文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor 1 竞赛信息 为了培养学生的创新意识及运用数…...

安卓手机变身Linux服务器
文章目录 前言一、准备工作1、安卓手机2、下载软件二、开始安装1、检查系统,确认版本并安装2、配置(安卓7.0 及以上的用户忽略此步)3、问题处理【没有异常的小伙伴忽略】总结前言 在实际开发中有很多地方都需要服务器资源,但是服务器资源不论在哪里都是比较紧缺的资源,今…...

【Ansible】Ansible自动化运维工具之playbook剧本
playbook 一、playbook 的概述1. playbook 的概念2. playbook 的构成 二、playbook 的应用1. 安装 httpd 并启动2. 定义、引用变量3. 指定远程主机 sudo 切换用户4. when条件判断5. 迭代6. Templates 模块6.1 添加模板文件6.2 修改主机清单文件6.3 编写 playbook 7. tags 模块 …...
Yolov8目标检测
Yolov8目标检测 目录 Yolov8目标检测一、准备数据集二、源码下载配置2.1 下载库2.2 修改配置2.3 训练2.4 验证2.5 测试2.6 模型导出2.7 本地测试 一、准备数据集 Yolov8只支持yolo格式的数据,所以,需要将数据集格式调整为 datasets|images|train|00000…...

Jmeter用于接口测试中,关联如何实现
Jmeter用于接口测试时,后一个接口经常需要用到前一次接口返回的结果,应该如何获取前一次请求的结果值,应用于后一个接口呢,拿一个登录的例子来说明如何获取。 1、打开jmeter, 使用的3.3的版本,新建一个测试计划&#x…...

线程状态
从卖包子的案例学习进程间的通信 public class Test {public static void main(String[] args) {Object objnew Object();Thread th1new Thread(){Overridepublic void run() {synchronized (obj){System.out.println("来三个包子!");try {obj.wait(); /…...

HTML一些基础知识
1、Web标准:主要包含结构、表现、行为。结构用于对网页元素进行整理和分类,主要指HTML。表现用于设置网页元素的板式、颜色、大小等外观样式,主要指的是CSS。行为主要指的是网页模型的定义以及交互的编写,主要是js文件。 Html相当…...
git 命令总结
一、本地分支和仓库里的分支不同步(本地看不到最新的分支) 1.使用 git fetch origin 或者git remote update origin --prune命令更新 2.git branch -r 查看 即可 二、git 合并代码 1. git 如何把分支代码合并到master 1.1 首先切换到分支 git checkou…...
【Django】如何优化数据库访问
原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、数据库层面优化常用优化postgresql查询分库分表 二、内存层面优化三、代码层面优化 前言 Django是一个高级的Web框架,它…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...

AD学习(3)
1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分: (1)PCB焊盘:表层的铜 ,top层的铜 (2)管脚序号:用来关联原理图中的管脚的序号,原理图的序号需要和PCB封装一一…...
iOS 项目怎么构建稳定性保障机制?一次系统性防错经验分享(含 KeyMob 工具应用)
崩溃、内存飙升、后台任务未释放、页面卡顿、日志丢失——稳定性问题,不一定会立刻崩,但一旦积累,就是“上线后救不回来的代价”。 稳定性保障不是某个工具的功能,而是一套贯穿开发、测试、上线全流程的“观测分析防范”机制。 …...
mcts蒙特卡洛模拟树思想
您这个观察非常敏锐,而且在很大程度上是正确的!您已经洞察到了MCTS算法在不同阶段的两种不同行为模式。我们来把这个关系理得更清楚一些,您的理解其实离真相只有一步之遥。 您说的“select是在二次选择的时候起作用”,这个观察非…...