Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >重新理解RocketMQ Commit Log存储协议

重新理解RocketMQ Commit Log存储协议

原创
作者头像
小伟
修改于 2023-04-06 10:01:22
修改于 2023-04-06 10:01:22
5.4K1
举报
文章被收录于专栏:魔都程序缘魔都程序缘

最近突然感觉:很多软件、硬件在设计上是有root reason的,不是by desgin如此,而是解决了那时、那个场景的那个需求。一旦了解后,就会感觉在和设计者对话,了解他们的思路,学习他们的方法,思维同屏:活到老学到老。

1. 大家思考

1.1 Consumer Queue Offset是连续的吗, 为什么?

1.2 Commit Log Offset是连续的吗, 为什么?

1.3 Java写的文件,默认是大端序还是小端序,为什么?

2. Commit Log真实分布

在大家思考之际, 我们回想下commit log是怎么分布的呢?

在Broker配置的存储根目录下,通过查看Broker实际生成的commit log文件可以看到类似下面的数据文件分布:

Broker真实数据文件存储分布
Broker真实数据文件存储分布

可以看到,真实的存储文件有多个, 每一个都是以一串类似数字的字符串作为文件名的,并且大小1G。

我们结合源码可以知道,实际的抽象模型如下:

Commit Log存储文件分布抽象
Commit Log存储文件分布抽象

由上图得知:

  • 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

append加锁
append加锁

我们看到Commit Log文件中有很多个消息,按照既定的协议存储的,那具体协议是什么呢, 你是怎么知道的呢?

3. Commit Log存储协议

关于Commit Log存储协议,我们问了下ChatGPT, 它是这么回复我的,虽然不对,但是这个回复格式和说明已经非常接近答案了。

ChatGPT回复
ChatGPT回复

我们翻看源码,具体说明下:https://github.com/apache/rocketmq/blob/rocketmq-all-4.9.3/store/src/main/java/org/apache/rocketmq/store/CommitLog.java#L1547-L1587

Commit Log存储协议
Commit Log存储协议

我整理后, 如下图;

我理解的Commit Log存储协议
我理解的Commit Log存储协议

说明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个,大家找找?

我们看到这个协议后,如何证明你的物理文件就是按照这个协议写的呢?

4. 用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-import
golang-import

这里贴了一段golang中解析Commit Log Offset的例子:在java中这个offset是一个long类型,占用8个字节。

在golang中,读取8个字节长度的数据,并且按照大端序解码为int64,就可以得到正常的Commit Log Offset。

Golang-demo
Golang-demo

我跑了一个demo结果,大家参考:

读取consumer-queue-commit-log
读取consumer-queue-commit-log

5. 回答最初的问题

以下为个人见解,大家参考:

1.1 Consumer Queue Offset是连续的吗, 为什么?

是连续的。

consumer queue offset,是指每个queue中索引消息的下标,下标当然是连续的。消费者也是利用了这个连续性,避免消费位点提交空洞的。

每个索引消息占用相同空间,都是20字节,结构如下:

consumer-queue索引消息结构
consumer-queue索引消息结构

这里物理位点也就是Commit Log Offset。

1.2 Commit Log Offset是连续的吗, 为什么?

不是连续的。

Commit Log Offset是指的每个消息在全部Commit Log文件中的字节偏移量, 每个消息的大小是不确定的,所以Commit Log Offset,也即是字节偏移量肯定是不一样的。

并且可以知道,每两个偏移量的差的绝对值就是前一个消息的消息字节数总长度。

并且上文中图 “Commit Log存储文件分布抽象”中的有误解,每个小方格的大小其实是不一样的。

1.3 Java写的文件,默认是大端序还是小端序,为什么?

大端序。字节序其实有数据存储顺序和网络传输顺序两种,java中默认用的大端序,保持和网络传输一样,这样方便编解码。

每段网络传输层的数据报文最前面的字节是表达后面的数据是用什么协议传输的,这样数据接收者在接受数据时, 按照字节顺序,先解析协议,再根据协议解码后面的字节序列,符合人类思考和解决问题的方式。

以上是我的理解,有任何问题,加我微信细聊。

微信二维码
微信二维码

讨论说明:由于RocketMQ一些版本可能有差异,本文在4.9.3版本下讨论,大家可以参考这个方法,解开5.0甚至其他版本,其他数据文件的存储协议格式。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
1 条评论
热度
最新
很详细
很详细
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
重新理解RocketMQ Commit Log存储协议
最近突然感觉:很多软件、硬件在设计上是有root reason的,不是by desgin如此,而是解决了那时、那个场景的那个需求。一旦了解后,就会感觉在和设计者对话,了解他们的思路,学习他们的方法,思维同屏:活到老学到老。 问题思考 1、Consumer Queue Offset是连续的吗, 为什么? 2、Commit Log Offset是连续的吗, 为什么? 3、Java写的文件,默认是大端序还是小端序,为什么? Commit Log真实分布 在大家思考之际, 我们回想下commit log是怎么分
腾讯云中间件团队
2023/05/19
2750
重新理解RocketMQ Commit Log存储协议
rocketmq原理与实战解析_rocketmq底层原理
Namesrv接收Broker注册的topic信息, namesrv只存内存,但是broker有任务定时推送
全栈程序员站长
2022/09/19
6860
rocketmq原理与实战解析_rocketmq底层原理
RocketMQ为什么这么快?我从源码中扒出了10大原因!
如果你对RocketMQ还不了解,可以从公众号后台菜单栏中查看我之前写的关于RocketMQ的几篇文章
三友的java日记
2024/03/18
4770
RocketMQ为什么这么快?我从源码中扒出了10大原因!
深度解读 RocketMQ 存储机制
RocketMQ 实现了灵活的多分区和多副本机制,有效的避免了集群内单点故障对于整体服务可用性的影响。存储机制和高可用策略是 RocketMQ 稳定性的核心,社区上关于 RocketMQ 目前存储实现的分析与讨论一直是一个热议的话题。近期我一直在负责 RocketMQ 消息多副本和高可用能力的建设,和大家分享下一些有趣的想法。
从大数据到人工智能
2022/09/08
7720
面渣逆袭:RocketMQ二十三问
选择中间件的可以从这些维度来考虑:可靠性,性能,功能,可运维行,可拓展性,社区活跃度。目前常用的几个中间件,ActiveMQ作为“老古董”,市面上用的已经不多,其它几种:
三分恶
2022/05/11
1.3K0
面渣逆袭:RocketMQ二十三问
RocketMQ存储--消息追加【源码笔记】
commitLog内存(ByteBuffer)写入位点,标记消息写到哪了,下次从该位置开始写。
瓜农老梁
2019/08/20
9980
RocketMQ存储--消息追加【源码笔记】
RocketMQ
系统的耦合性越高,容错性就越低。以电商应用为例,用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障或者因为升级等原因暂时不可用,都会造成下单操作异常,影响用户使用体验。
JokerDJ
2023/11/27
1.8K0
RocketMQ
RocketMQ 设计原理与最佳实践
RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。
Java识堂
2021/06/01
1.2K0
RocketMQ 设计原理与最佳实践
RocketMQ原理—4.消息读写的性能优化
Producer发送消息时需要指定一个Topic,需要知道Topic里有哪些Queue,以及这些Queue分别分布在哪些Broker上。因此,Producer发送消息到Broker的流程如下:
东阳马生架构
2025/04/03
1520
10 张图告诉你 RocketMQ 是怎样保存消息的
首先,在 RocketMQ 集群中创建一个 Topic,叫做 MyTestTopic,配置如下图:
jinjunzhu
2022/12/20
9140
10 张图告诉你 RocketMQ 是怎样保存消息的
RocketMQ分析——高并发读写
生产者发送消息有负载均衡。生产者发送消息时,会自动轮询当前所有可发送的broker,一条消息发送成功,下次换另外一个broker发送,以达到消息平均落到所有的broker上。
用户5325874
2020/04/16
2.8K1
消息中间件—RocketMQ消息存储(二)一、RocketMQ存储整体设计架构回顾二、RocketMQ存储关键技术—再谈Mmap与PageCache三、RocketMQ存储优化技术四、RocketMQ
文章摘要:上篇中主要介绍了RocketMQ存储部分的整体架构设计,本篇将深入分析RocketMQ存储部分的细节内容 在本篇文章中,小编将继续深入分析与介绍RocketMQ消息存储部分中的关键技术—Mmap与PageCache、几种RocketMQ存储优化技术(包括预先创建分配MappedFile、文件预热和mlock系统调用)、RocketMQ内部封装类—CommitLog/MappedFile/MappedFileQueue/ConsumeQueue的简析。然后,再简要介绍下RocketMQ消息刷盘两种主要方式。在读完本篇幅后,希望读者能够对RocketMQ消息存储部分有一个更为深刻和全面的认识。
用户2991389
2018/10/10
5.1K3
第五章 RocketMQ工作原理
Producer可以将消息写入到某Broker中的某Queue中,其经历了如下过程:
RookieCyliner
2025/06/04
1230
后端程序员必备:RocketMQ相关流程图/原理图
RocketMQ是开源的消息中间件,它主要由NameServer,Producer,Broker,Consumer四部分构成。
捡田螺的小男孩
2020/04/15
2.2K0
后端程序员必备:RocketMQ相关流程图/原理图
云原生中间件RocketMQ(一)基本概念&功能特性&架构设计&环境搭建
消息队列(Message Queue,简称 MQ)是构建分布式互联网应用的基础设施,通过 MQ 实现的松耦合架构设计可以提高系统可用性以及可扩展性,是适用于现代应用的最佳设计方案。
共饮一杯无
2022/11/28
1K0
云原生中间件RocketMQ(一)基本概念&功能特性&架构设计&环境搭建
消息的存储-RocketMQ知识体系3
上一篇了解了RocketMQ消息发送,本文开始聊聊消息发送到Broker端后,消息存储相关的逻辑。
DougWang
2021/07/21
5710
快速学习-RocketMQ设计理念
消息存储是RocketMQ中最为复杂和最为重要的一部分,本节将分别从RocketMQ的消息存储整体架构、PageCache与Mmap内存映射以及RocketMQ中两种不同的刷盘方式三方面来分别展开叙述。
cwl_java
2020/09/18
7400
深入剖析 RocketMQ 源码 - 消息存储模块
RocketMQ 是阿里巴巴开源的分布式消息中间件,它借鉴了 Kafka 实现,支持消息订阅与发布、顺序消息、事务消息、定时消息、消息回溯、死信队列等功能。RocketMQ 架构上主要分为四部分,如下图所示:
2020labs小助手
2021/11/09
1.5K0
?【Alibaba中间件技术系列】「RocketMQ技术专题」服务底层高性能存储设计分析
消息中间件的本身定义来考虑,应该尽量减少对于外部第三方中间件的依赖。一般来说依赖的外部系统越多,也会使得本身的设计越复杂,采用文件系统作为消息存储的方式。
码界西柚
2022/01/23
7700
?【Alibaba中间件技术系列】「RocketMQ技术专题」服务底层高性能存储设计分析
面试系列之-rocketmq文件数据存储
Broker上的Topic上的消息都会顺序的写入到commitlog文件下,然后再异步转存到consumequeue以及indexFile文件;该消息的元信息存储着消息所在的Topic与Queue,当消费者要进行消费时,会通过ConsumerQueue文件来找到自己想要消费的队列;该队列不存储具体的消息,而是存储消息的基本信息与偏移量。消费者通过偏移量去CommitLog中找到自己需要消费的信息然后取出,就可以进行消费;并且Broker还可以对CommitLog来建立Hash索引文件IndexFile,这样就可以通过消息的key来找到消息;
用户4283147
2022/12/29
7040
面试系列之-rocketmq文件数据存储
推荐阅读
相关推荐
重新理解RocketMQ Commit Log存储协议
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档