当前位置: 首页 > news >正文

图解RocketMQ之消息如何存储

大家好,我是苍何。

人一辈子最值得炫耀的不应该是你的财富有多少(虽然这话说得有点违心,呵呵),而是你的学习能力。技术更新迭代的速度非常快,那作为程序员,我们就应该拥有一颗拥抱变化的心,积极地跟进。

在学习 RocketMQ 的消息存储之前,我们已经学习了 topic 主题、消息模型、消息的过滤和重试等知识点。

这让我感觉自己富有极客精神,非常良好。

我好快乐

小伙伴们在继续阅读之前,我必须要声明一点,为一名负责任的技术博主,我是动了心的,这篇教程,小伙伴们读完后绝对会感到满意,忍不住无情地点赞,以及赤裸裸地转发

当然了,小伙伴们遇到文章中有错误的地方,不要手下留情,可以组团过来捶我,但要保证一点,不要打脸,我怕毁容。

我们都知道,消息队列一大核心功能是削峰填谷,也就是在大流量场景下(比如 12306 春运购票),将部分业务逻辑放在 MQ,等其慢慢处理,且给用户友好提示:

“您已加入候补队列,请耐心等待!”

在 MQ 中的消息,可以有条不紊的、均匀的消费,但需要保证消息存储的可靠性

不可能我加入候补半天,让我等,我等了 2 天,然后提示我压根没加入候补,这不是坑人吗?

mq宕机后消息都丢了

所以,我们需要动员脑子里所有脑细胞,仔细思考下,MQ 中的 broker 该如何存储消息才能防止消息丢失呢?

消息可以存 MySQL 吗

要防止数据不会在持久化的时候消失,很多的做法都是将数据库直接存在 MySQL,比如 Nacos 持久化、Redis 持久化。

那 RocketMQ 可以把消息存储在 MySQL 吗?

单纯从持久化来看,没问题,但消息可不单单是做持久化,需要满足削峰填谷需求,MySQL 性能就无法满足了。

如果 MySQL 可以,那我干嘛费老半天劲把消息丢到 MQ 呢?我直接丢 MySQL 处理不就得了?

这时估计 MySQL 他老人家也会想"合着折腾半天,最后又回到我这了是吧?"

消息可以存 MySQL 吗

消息可以存 Redis 吗

这个时候你聪明的脑袋瓜肯定灵机一动,那要想追求高性能,存 Redis 啊,Redis 贼快,而且还可以持久化,这下可以了吧?

Redis 就像是个 mini 冰箱,虽然取东西快,但空间有限。RocketMQ可是要处理海量消息的"大胃王",用硬盘这个"大冷库"才够塞。

Redis 虽然也能持久化,但更像是给冰箱拍照。RocketMQ 需要的是 365 天 24 小时不间断运转的"冷库"级别持久化。

处于性能的考虑,Redis 读写虽然很快,毕竟还是操作内存,但要在内存和磁盘间倒腾数据就慢了。

Redis说:臣妾做不到啊

还有一个核心问题是,如果真是把消息放 Redis 了,那又引入了第三方组件,合着,我想用个 RocketMQ,你还得硬要我搞个 Redis。Redis 要宕了,RocketMQ 也嗝屁了。

软件工程,不是越复杂越好,和生活一样,往往大道至简的东西才更优雅,故而 RocketMQ 是绝对不可能吧消息丢给 Redis 的。

消息存哪里

这时,你肯定会没耐心的对苍何想要拳打脚踢,说这么半天,那消息到底存在哪儿?

先说结论:消息存本地磁盘

是不是简单粗暴?反正最后不管是 MySQL 还是 Redis,持久化都要存磁盘,那我直接绕过中间商,不更优雅吗?

磁盘存储绕过中间商

问题很多的小明又问了,磁盘也不可靠啊,不是照样会损坏?

但现在服务器上都要做 RAID,有备份在,那如果服务器直接被炸了呢?(虽然这种概率很小)

那还可以多云融合(就是多个云服务器备份),异地容灾等,这里就不展开了,总之,道高一尺,魔高一丈。

极致的可靠是不存在的,我们只能在我们能想到的合理范围内做到可靠,这就是互联网。

你可能会问,存到磁盘上,那是如何存储的呢?

假如有很多个 topic,每个 topic 又有很多个队列,是每个 topic 一个文件?还是每个队列一个文件?

commitlog

为了保证 RocketMQ 的写性能,最好是将所有消息都放在一个文件,并顺序读、顺序写

如果不放在一个文件,硬盘的存储物理位置就不是连续的,能无法保证顺序写,这个时候写入后的物理位置其实就是随机的了。

顺序读写也是为了追求极致的性能,这个其实和 MySQL 的 redo log 有异曲同工之妙。

而这个存储消息的本地文件,就叫做 commitlog。位于 rocketmq/data 文件夹下面。

commitLog所在位置

当你用你粗壮的手准备打开这个文件时,发现是个二进制文件。

commitLog是个二进制文件

这也很好理解,使用二进制存储,一来节省存储空间,二来也能提高读取性能

要想打开读取这文件,可以借助 RocketMQ 自带的 mqadmin 来读取,比如:

# 使用rocketmq-tools查看消息
sh mqadmin queryMessageByKey -n <namesrvAddr> -t <topic> -k <messageKey>

当然也可以使用开源工具如 rocketmq-dump 来查看,小伙伴们可以亲自试试。

consumequeue

细心的小伙伴可能已经注意到除了 commitlog 还有一个文件 consumequeue,那这里面存的是啥子呢?

我们知道 commitlog 存的是消息的全量数据,那对于消费者来说,想要知道自己该消费哪条消息,我们在之前的文章中分析过,靠的是消费位点(comsumerOffset),也就是消息的记录。

这个 comsumerOffset 也是会落在磁盘持久化的。

commitlog 里面只有一个文件,里面存的是消息的全量信息,为了追求极致的性能体验,肯定是需要索引来进行查询。

consumequeue 存放的是起始偏移量和长度,相当于这个索引。

通过起始偏移量和长度可以查询 commitlog 中的全量消息信息。

为什么这么做呢?

文件下标对应关系

假设 commitlog 存了 2 条消息,分别是 ABC、012,那对应的文件内容是 ABC012,每个字节会对应一个下标,比如:

A:0
B:1

我们要想读到 ABC 这条消息,只需要知道起始的 A 对应的下标,以及消息的长度就可以拿到这条消息了。这个下标其实就是偏移量

通过起始下标和长度可以拿到消息

所以 consumequeue 中存的就是消息的起始偏移量和长度。

consumequeue存的是啥子?

那么现在我们来梳理下消息存储的流程吧:

RocketMQ 先将消息存到 commitlog,然后通过定时任务把消息的起始偏移量和长度存到 consumequeue,然后根据这两个数据定位到消息,在 consumequeue 其实就已经按照 topic 和队列分好了,查找起来也是相当快的。

消费者消费消息的时候,通过消费位点找到 consumequeue 里面的起始偏移量和长度,通过索引找到 commitlog 对应的全量消息,然后再消费。

消息存储和消费流程

消息索引

细心的小伙伴可能会注意到通过起始偏移量和长度来定位消息,着实有些慢,并不能快速查找到消息。

RocketMQ 提供了消息索引机制。5. x 中是位于 index 文件夹中,存放的就是索引信息。(这个索引更快👍)

消息索引

索引的内部通过数据槽来实现,感兴趣的小伙伴可以去了解下内部实现原理。

通常我们会将业务唯一 id 设置为索引,比如订单号,查询订单号就能立刻查询出当前订单的消息。

那么如何添加索引呢?

发送消息的时候,可以添加索引:

Message msg = new Message("TopicTest", "TagA", "Hello RocketMQ".getBytes());
msg.setKeys("yourKey");

broker 配置中需要做下设置:

messageIndexEnable=true
messageIndexSafe=false

最后

不得不说,一个优秀的中间件,往往会有很多精妙的设计,RocketMQ 的消息存储机制的设计就堪称完美。

当然,还有更多的细节,比如 commitlog 的加载流程、索引的存储结构,这些大家感兴趣的可以自行查阅资料哈。

好啦,今天的分享结束。

我是苍何,这是图解 RocketMQ 教程的第 8 篇,我们下篇见~

相关文章:

图解RocketMQ之消息如何存储

大家好&#xff0c;我是苍何。 人一辈子最值得炫耀的不应该是你的财富有多少&#xff08;虽然这话说得有点违心&#xff0c;呵呵&#xff09;&#xff0c;而是你的学习能力。技术更新迭代的速度非常快&#xff0c;那作为程序员&#xff0c;我们就应该拥有一颗拥抱变化的心&…...

2024年中国信创产业发展白皮书精简版

获取方式&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEHMfcCfJm4A40vzrewoCw?pwda5u1 提取码&#xff1a;a5u1 得益于中国数字经济的迅猛发展&#xff0c;2023年中国信创产业规模达20961.9亿元&#xff0c;2027年有望达到37011.3亿元&#xff0c;中国信创市场…...

Redis2-Redis常见命令

目录 Redis数据结构介绍 Redis通用命令 KEYS DEL EXISTS EXPIRE String类型 Key的层级格式 Hash类型 List类型 Set类型 SortedSet类型 Redis数据结构介绍 Redis是一个key-value的数据库&#xff0c;key一般是String数据库&#xff0c;value的类型多种多样 可以通过…...

一天攻克一个知识点 —— 设计模式之动态代理

一、设计模式之代理设计 代理设计是在Java开发中使用较多的一种设计模式&#xff0c;所谓的代理设计模式就是指一个代理主体操作真实主体&#xff0c;真实主体操作具体业务&#xff0c;代理主体负责给具体业务添砖加瓦。 就好比在生活中你有一套房子想要出租(你真实主体)&…...

数据采集与预处理【大数据导论】

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 数据采集与预处理前 必看 【大数据导论】—大数据序…...

白骑士的PyCharm教学进阶篇 2.2 高级调试技术

系列目录 上一篇&#xff1a;白骑士的PyCharm教学进阶篇 2.1 高效编码技巧 在Python开发中&#xff0c;调试是一个非常重要的环节。PyCharm作为一款功能强大的IDE&#xff0c;不仅提供了基本的调试功能&#xff0c;还包含了许多高级调试工具与技巧。本篇将详细介绍这些高级调试…...

[网鼎杯]2018Unfinish

使用ctf在线靶场https://adworld.xctf.org.cn/home/index。 进入靶场&#xff0c;发现是一个登录页面。 使用awvs进行扫描&#xff0c;发现存在login.php和register.php&#xff0c;并且register.php存在sql注入漏洞。 访问一下register.php试试&#xff0c;发现是一个注册页面…...

Java算法-力扣leetcode-383. 赎金信

383. 赎金信 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1a…...

使用idea对spring全家桶的各种项目进行创建

目录 1. 简介2. spring2.1 简介2.2 创建 3. springmvc3.1 介绍3.2 创建 4. springboot4.1 简介4.2 创建&#xff08;仅仅就其中一种&#xff09; 5. 其他&#xff1a;maven6. 参考链接 1. 简介 因为总是分不清spring全家桶&#xff0c;所以就在这里进行一个总结。 2. spring …...

FAT32、NTFS、FAT的区别

FAT&#xff08;File Allocation Table&#xff09; 特点 簇大小限制&#xff1a;FAT文件系统的簇大小是固定的&#xff0c;这限制了单个文件的大小和文件系统的效率。 存储效率&#xff1a;由于簇大小的限制&#xff0c;FAT文件系统在存储小文件时可能会浪费空间。 文件系统结…...

捉虫笔记(二)之 杀软请你自重点

捉虫笔记&#xff08;二&#xff09;之 杀软请你自重点 前一篇文章介绍了如何配置符号&#xff0c;这一篇文章我们来个实战。 1 现象 在我们的程序中利用robocopy进行文件的复制。但是QA反馈&#xff0c;只要进行了备份操作&#xff0c;整个进程就会卡住。但是奇怪的是只有他…...

python学习之路 - python的函数

目录 一、python函数1、函数介绍2、函数的定义3、函数的参数4、函数的返回值5、函数说明文档6、函数的嵌套调用7、变量的作用域8、综合案例9、函数与方法的区别 二、python函数进阶1、函数多返回值2、函数多种传参方式a、位置参数b、关键字参数c、缺省参数d、不定长参数 3、匿名…...

使用SpringBoot+Vue3开发项目(2)---- 设计文章分类的相关接口及页面

目录 一.所用技术栈&#xff1a; 二.后端开发&#xff1a; 1.文章分类列表渲染&#xff1a; 2.新增文章分类&#xff1a; 3.编辑文章分类&#xff1a; 4.删除文章分类 &#xff1a; 5.完整三层架构后端代码&#xff1a; &#xff08;1&#xff09;Controller层&#xff1a…...

Layui---toolbar与 tool的区别

table.on(toolbar): table.on(toolbar)&#xff1a; 这个事件监听器是用来处理表格工具栏的事件。工具栏通常位于表格的上方&#xff0c;可以包含添加、删除、导出等按钮。当用户与这些工具栏中的按钮交互时&#xff0c;比如点击一个按钮来添加新行或者进行搜索操作&#xff0c…...

U-Net++原理与实现(含Pytorch和TensorFlow源码)

U-Net原理与实现 引言1. U-Net简介1.1 编码器&#xff08;Encoder&#xff09;1.2 解码器&#xff08;Decoder&#xff09;1.3 跳跃连接&#xff08;Skip Connections&#xff09; 2. U-Net详解2.1 密集跳跃连接2.2 嵌套和多尺度特征融合2.3 参数效率和性能2.4 Pytorch代码2.5 …...

产品心理学:啦啦队效应

电视里我们常会看见这样一个场景&#xff0c;一群女孩穿着短裙有说有笑地在大街上走过&#xff0c;把路人们都看傻了&#xff0c;其实单个来看&#xff0c;她们的长相并不出众&#xff0c;可是凑在一起就显得青春貌美&#xff0c;这就是“啦啦队效应”——cheerleader effect。…...

AC+AP组网

配置DHCP Switch1 <Huawei>sys [Huawei]undo in en [Huawei]vlan batch 10 20 30 40[Huawei]int vlan 10 [Huawei-Vlanif10]ip add 192.168.10.1 24 [Huawei-Vlanif10]quit[Huawei]int vlan 20 [Huawei-Vlanif20]ip add 192.168.20.1 24 [Huawei-Vlanif20]quit[Huawei]…...

2024.8.05(glibc的安装及MySQL的安全用户角色权限)

一、glibc的安装 1、清空/etc目录下的my.cnf [rootlocalhost ~]# ls -l /etc/my.cnf -rw-r--r--. 1 root root 570 6月 8 2017 /etc/my.cnf [rootlocalhost ~]# rm -rf /etc/my.cnf 2、删除mariadb [rootlocalhost ~]# yum -y remove mariadb [rootlocalhost ~]# find / -na…...

【精选】6款一键生成论文的软件3000字论文网站

千笔-AIPassPaPer是一款功能强大且全面的AI论文写作工具&#xff0c;特别适合学术研究者和学生使用。它不仅能够一键生成高质量的论文初稿&#xff0c;还涵盖了700多个学科专业方向&#xff0c;满足各种学术需求。 一、千笔-AIPassPaPer 传送门&#xff1a;https://www.aipape…...

如何使用 PHP Simple HTML DOM Parser 轻松获取网页中的特定数据

背景介绍 网页数据的抓取已经成为数据分析、市场调研等领域的重要工具。无论是获取产品价格、用户评论还是其他公开数据&#xff0c;网页抓取技术都能提供极大的帮助。今天&#xff0c;我们将探讨如何使用 PHP Simple HTML DOM Parser 轻松获取网页中的特定数据。PHP Simple H…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...