RocketMQ存储设计的奥妙

news2025/2/24 17:56:10

RocketMQ作为一款基于磁盘存储的中间件,具有无限积压能力,并提供高吞吐、低延迟的服务能力,其最核心的部分必然是它优雅的存储设计。

1、存储概述

RocketMQ存储的文件主要包括Commitlog文件、ConsumeQueue文件、Index文件。

RocketMQ将所有主题的消息存储在同一个文件中,确保消息发送时按顺序写文件,尽最大能力确保消息发送的高可用性与高吞吐量。

但消息中间件一般都是基于主题的订阅与发布模式,消息消费时必须按照主题进行帅选消息,显然从Commitlog文件中按照topic去筛选消息会变得及其低效,为了提高根据主题检索消息的效率,RocketMQ引入了ConsumeQueue文件,俗成消费队列文件。

关系型数据库可以按照字段属性进行记录检索,作为一款主要面向业务开发的消息中间件,RocketMQ也提供了基于消息属性的检索能力,底层的核心设计理念是为Commitlog文件建立哈希索引,并存储在Index文件中

在RocketMQ中顺序写入到Commitlog文件后,ConsumeQueue与Index文件都是异步构建的,其数据流向图如下: 在这里插入图片描述

2、存储文件组织方式

RocketMQ在消息写入过程中追求极致的磁盘顺序写。所有主题的消息全部写入一个文件,即Commitlog文件。所有消息按抵达顺序依次追加到文件中,消息一旦写入,不支持修改。Commitlog文件的具体布局如下图所示: 在这里插入图片描述 基于文件编程与基于内存编程有一个很大的不同是在基于内存的编程模式中我们有现成的数据结构,例如 List、HashMap,对数据的读写非常方便,那么一条一条消息存入文件Commitlog后,该如何查找呢?

正如关系型数据会为每一条数据引入一个ID字段,在基于文件编程的模型中,也会为一条消息引入一个身份标志:消息物理偏移量,即消息存储在文件的起始位置。

正是有了物理偏移量的概念,Commitlog的文件名命名也是极具技巧性,使用了存储在该文件的第一条消息在整个Commitlog文件组中的偏移量来命名,例如第一个 Commitlog文件为 0000000000000000000,第二个文件为00000000001073741824,然后依次类推。

这样做的好处是给出任意一个消息的物理偏移量,例如消息偏移量为 73741824,可以通过二分法进行查找,快速定位这个文件在第一个文件中,然后用消息的物理偏移量减去该文件的名称所得到的差值,就是在该文件中的绝对地址。

Commitlog文件的设计理念是追求极致的消息写,但我们知道消息消费模型是基于主题的订阅机制,即一个消费组是消费特定主题的消息。如果根据主题从commitlog文件中检索消息,我们会发现这绝不是一个好主意,只能从文件的第一条消息逐条检索,其性能可想而知,故为了解决基于topic的消息检索问题,RocketMQ引入了consumequeue文件,consumequeue的结构如下图所示。 在这里插入图片描述 ConsumeQueue文件是消息消费队列文件,是Commitlog文件基于Topic的索引文件,主要用于消费者根据Topic消费消息,其组织方式为/topic/queue,同一个队列中存在多个文件。

Consumequeue的设计极具技巧,每个条目长度固定(8字节commitlog物理偏移量、4字节消息长度、8字节tag hashcode)。

这里不是存储tag的原始字符串,而选择存储hashcode,目的就是确保每个条目的长度固定,可以使用访问类似数组下标的方式快速定位条目,极大地提高了ConsumeQueue文件的读取性能。

试想一下,消息消费者根据topic、消息消费进度(consumeuqe逻辑偏移量),即第几个Consumeque条目,这样的消费进度去访问消息的方法为使用逻辑偏移量logicOffset * 20即可找到该条目的起始偏移量(consumequeue文件中的偏移量),然后读取该偏移量后20个字节即得到一个条目,无须遍历consumequeue文件。

RocketMQ与Kafka相比具有一个强大的优势,就是支持按消息属性检索消息,引入consumequeue文件解决了基于topic查找的问题,但如果想基于消息的某一个属性查找消息,consumequeue文件就无能为力了。

RocketMQ引入了Index索引文件,实现基于文件的哈希索引。IndexFile的文件存储结构如下图所示: 在这里插入图片描述 IndexFile文件基于物理磁盘文件实现Hash索引。其文件由40字节的文件头、500万个哈希槽,每个哈希槽4个字节,最后由2000万个Index条目,每个条目由20个字节构成,分别为4字节索引key的hashcode、8字节消息物理偏移量、4字节时间戳、4字节的前一个Index条目(哈希冲突的链表结构)。

即建立了索引Key的hashcode与物理偏移量的映射关系,根据key先快速定义到commitlog文件,关于Hash索引具体到工作机制,可以参考笔直《RocketMQ技术内幕》第二版4.5.3节的详细介绍

3、顺序写

基于磁盘的读写,提高其写入性能的另外一个设计原理是磁盘顺序写

磁盘顺序写广泛用在基于文件的存储模型中,大家不妨思考一下 MySQL Redo 日志的引入目的,我们知道在 MySQL InnoDB 的存储引擎中,会有一个内存 Pool,用来缓存磁盘的文件块,当更新语句将数据修改后,会首先在内存中进行修改,然后将变更写入到 redo 文件(刷写到磁盘),然后定时将InnoDB内存池中的数据刷写到磁盘。 在这里插入图片描述 为什么不一有数据变更,就直接更新到指定的数据文件中呢?以MySQL InnoDB中一个库存在上千张,每一个张的数据会使用单独的文件存储,如果每一个表的数据发生变更,就刷写到磁盘,就会存在大量的随机写入,性能无法得到提升,故引入一个redo文件,顺序写redo文件,从表面上多了一步刷盘操作,但由于是顺序写,相比随机写,带来的性能提升是非常显著的。

4、内存映射机制

虽然基于磁盘的顺序写可以极大提高IO的写效率,但如果基于文件的存储采用常规的JAVA文件操作API,例如 FileOutputStream等,其性能提升会很有限,RocketMQ引入了内存映射,将磁盘文件映射到内存中,以操作内存的方式操作磁盘,性能又提升了一个档次。

在JAVA中可通过FileChannel的map方法创建内存映射文件。

在Linux服务器中由该方法创建的文件使用的就是操作系统的pagecache,即页缓存。

Linux操作系统中的内存使用策略时会尽可能地利用机器的物理内存,并常驻内存中,就是所谓的页缓存。在操作系统的内存不够的情况下,采用缓存置换算法,例如LRU将不常用的页缓存回收,即操作系统会自动管理这部分内存。

如果RocketMQ Broker进程异常退出,存储在页缓存中的数据并不会丢失,操作系统会定时将页缓存中的数据持久化到磁盘,做到数据安全可靠。不过如果是机器断电等异常情况,存储在页缓存中的数据就有可能丢失。

5、灵活多变的刷盘策略

有了顺序写和内存映射的加持,RocketMQ的写入性能得到了极大的保证,但凡事都有利弊,引入了内存映射和页缓存机制,消息会先写入到页缓存,此时消息并没有真正持久化到磁盘。那么broker收到客户端的消息发送后,是存储到页缓存中就直接返回成功,还是要持久化到磁盘中才返回成功呢?

这是一个“艰难”的抉择,是在性能与消息可靠性方面进行权衡。为此,RocketMQ提供了多种策略:同步刷盘、异步刷盘。

5.1 同步刷盘

同步刷盘在RocketMQ的实现中成为组提交,并不是每一条消息都必须刷盘。其设计理念如图所示: 在这里插入图片描述 采用同步刷盘,每一个线程将数据追到到内存后,并向刷盘线程提交刷盘请求,然后会阻塞;刷盘线程从任务队列中获取一个任务,然后触发一次刷盘,但并不只刷与请求相关的消息,而是会直接将内存中待刷盘的所有消息一次批量刷盘,然后就可以唤醒一组请求线程,实现组刷盘

5.2 异步刷盘

同步刷盘的优点是能保证消息不丢失,即向客户端返回成功就代表这条消息已被持久化到磁盘,即消息非常可靠,但这是以牺牲写入响应延迟性能为代价的,由于RocketMQ的消息是先写入 pagecache,故消息丢失的可能性较小,如果能容忍一定几率的消息丢失,可以考虑使用异步刷盘。

异步刷盘指的是broker将消息存储到pagecache后就立即返回成功,然后开启一个异步线程定时执行FileChannel的forece方法,将内存中的数据定时刷写到磁盘,默认间隔为500ms。

6、内存级读写分离

RocketMQ为了降低pagecache的使用压力引入了transientStorePoolEnable机制,即内存级别的读写分离机制。

默认情况下RocketMQ将消息写入pagecache,消息消费时从pagecache中读取,这样在高并发时pagecache的压力会比较大,容易出现瞬时broker busy,故RocketMQ还引入了transientStorePoolEnable,将消息先写入堆外内存并立即返回,然后异步将堆外内存中的数据提交到pagecache,再异步刷盘到磁盘中。其工作机制如下图所示: 在这里插入图片描述 消息在消费读取时不会尝试从堆外内存中读,而是从pagecache中读取,这样就形成了内存级别的读写分离,即消息写入时主要面对堆外内存,而读消息时主要面对pagecache。

该方案的优点是消息是直接写入堆外内存,然后异步写入pagecache。相比每条消息追加直接写入pagechae,其最大的优势是将消息写入pagecache操作批量化。

该方案的缺点是如果由于某些意外操作导致Broker进程异常退出,那么存储在堆外内存的数据会丢失,但如果是放入pagecache,broker异常退出并不会丢失消息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/10254.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

温振传感器有几种传输方式?

在现代化社会中,各种机器无时无刻参与着我们的日常生活,承担在我们的周围承担起重要作用,轴承、电机、泵体等也成为工业文明中关键存在,它们的温度和状态影响着整个工业自动化系统运行的健康和效率。 长期以来,传感器技…

数字集成电路设计(四、Verilog HDL数字逻辑设计方法)(一)

文章目录1.Verilog语言的设计思想和可综合特性2. 组合电路的设计2.1 数字加法器2.2 数据比较器2.3 数据选择器2.4 数字编码器2.4.1 3位二进制8线-3线编码器2.4.2 8线-3线优先编码器2.4.3 二进制转化十进制8421BCD编码器(重要)2.4.4 8421BCD十进制余3编码…

ue4使用Niagara粒子实现下雨效果,使用蓝图调节雨量

一、使用Niagara粒子系统实现下雨效果 1. 首先创建一个雨水的材质 新建 — 材质 2. 创建Niagara系统 新建 新建 — FX — Niagara系统 — 来自所选发射器的新系统 — 下一步 — 选择Fountain — 点击号,点击完成 删除下面的“Add Velocity in Cone” 添加“…

矩池云如何自定义端口,访问自己的web项目

本文将向您介绍如何在矩池云租用服务器的时候自定义端口,并将您的 web 项目部署到自定义端口,最后实现在本地通过自定义端口对应链接访问服务。 上传代码和数据 首先,您需要将本地的项目代码和数据上传到矩池云网盘。这里为了方便您测试使用…

类似ps的python工具lama cleaner

Lama Cleaner是个类似ps图片的工具,可以把图片中不想要的部分p掉,或者填补图片中丢失的部分。用下来感觉还蛮靠谱,对于不会ps的人是福音,记录一下。 相关介绍:https://github.com/Sanster/lama-cleaner 1.安装 安装…

react 中 ref 管理列表

背景 最近在看 react 新的官方文档 的时候,看到这么一个标题,How to manage a list of refs using a ref callback,就是一个图片的列表,类似这样 然后点击按钮的时候,通过 scrollIntoView 这个 api 来让他滚动&#…

python生成模拟微信气泡图片

0. 起因 众所周知,借刀杀人最为致命,聊天也是如此。 最近我的群聊画风逐渐变味: 当然,这种图片的生产成本很低,只需在设置页关闭昵称显示,把聊天背景重置为灰色,然后利用截图工具截图&#xf…

【金融项目】尚融宝项目(十三)

25、充值 25.1、需求介绍 25.1.1、投资人充值 **1、需求描述 ** 标的产生后,平台展示标的,投资人就可以在平台投资标的,获取收益;投资人投资标的必须满足以下条件: 充值过程与绑定过程一致,也是在平台发…

Delphi 11.2 Alexandria程序集代码

Delphi 11.2 Alexandria程序集代码 高DPI VCL设计器-VCL设计器现在在设计时使用类似Microsoft Windows的样式,这意味着除非禁用此功能,否则设计器中的控件始终使用此样式绘制。此样式与Windows当前使用的浅色或深色主题相匹配。 编辑器选项卡-在版本11.2…

【3D目标检测】Frustum PointNets for 3D Object Detection from RGB-D Data

目录概述细节网络结构视锥候选框3D实例分割边界框参数回归损失函数概述 首先本文是基于图像和点云的,属于早期的模态融合的成果,是串行的算法,而非并行的,更多的是考虑如何根据图像和点云这两个模态的数据进行3D目标检测。 提出动…

亚马逊平台不给力?来Starday,告诉你什么是真正的高阶玩法

距2021年的亚马逊封号潮已经过去了一段时间,但其影响却依然在跨境电商行业间回荡。从4月份起,亚马逊就开始对违反平台规则的卖家进行封号。此后打击规模持续扩大,到6月中下旬,深圳一批头部卖家均被亚马逊平台下架,遭到…

Coverage-based Greybox Fuzzing as Markov Chain

AFLFast: Coverage-based Greybox Fuzzing as Markov Chain 一、论文阅读 论文来自CCS2016 作者:Marcel Bhme 模糊测试领域巨佬 Abstract 基于覆盖的灰盒模糊测试 Coverage-based Greybox Fuzzing (CGF)。大多数测试用例执行少数高频路径,制定策略倾…

浪潮信息工程师:谈一谈设备透传虚拟机启动慢背后的原因及其优化方法 | 第 51 期

本周「龙蜥大讲堂」预告来啦!龙蜥社区邀请了浪潮信息操作系统研发工程师崔士伟分享《设备透传虚拟机的快速启动优化》,快来扫码入群,预定前排小板凳观看直播吧! 直播主题及内容介绍 直播主题:设备透传虚拟机的快速启…

360+城市空气质量指数-日度数据、良好天数统计(2001-2022年)

360城市空气质量指数-日度数据、良好天数统计(2001-2022年) 城市空气质量指数-日度数据、良好天数统计 1、包括:360个城市 2、时间:2001.1-2022.1月 3、样本量:1371937条 4、数据来源:空气质量在线…

使用Excel 表示汽车、摩托车10年免检时间、非常清晰。

1,汽车摩托车10年内年检问题 根据最新的国家法律: http://www.wenjiang.gov.cn/wjzzw/c152333/2022-09/30/content_66efe4febb8040758f3f079cf0baa310.shtml 搜索了下,找到了成都的规定: 近日,公安部、市场监管总局…

中电海康-中电52所面经

中电海康,中电52所面经中电海康面经一面(电话面)二面(现场面)自我回顾中电海康面经 一面(电话面) Redis的使用和配置多线程的使用,线程池的使用SpringBoot的核心注解和流程AOP IOC …

java项目-第133期ssm物流服务管理平台系统-java毕业设计

java项目-第133期ssm物流服务管理平台系统-毕业设计 【源码请到资源专栏下载】 今天分享的项目是《物流服务管理平台系统》 该项目分为前台和后台。主要分成三个角色:游客、普通管理员、管理员三个角色。 游客就是用户,只要是访问系统前台的用户都可以算…

华为防火墙的四种智能选路方式

FW支持四种智能选路方式,不同的智能选路方式可以满足不同的需求,管理员可以根据设备和网络的实际情况进行选择。 表1 智能选路方式 智能选路方式 定义 根据链路带宽负载分担 FW按照带宽比例将流量分配到各条链路上。带宽大的链路转发较多的流量&…

【我的渲染技术进阶之旅】基于Filament渲染引擎绘制一个不停旋转的彩色矩形

一、绘制三角形回顾 在上一篇博客 【我的渲染技术进阶之旅】Google开源的基于物理的实时渲染引擎Filament源码分析:Android版本的Filament第一个示例:sample-hello-triangle 中,我们分析了如何使用Filament来绘制一个三角形,效果如下所示,有一个不停旋转的彩色三角形: …

“外卷”的羽绒服

【潮汐商业评论/ 原创】 2022年的寒潮要比以往来得更早。 “你能想到我今年的第一件羽绒服竟然是在十一期间买的。”没等上“双十一”的车,Eva在国庆期间就已下单了“秋天的第一件羽绒服”。把保暖战线拉长的也不止Eva一个人,据浙商证券研报显示&#…