36.RocketMQ之Broker如何实现磁盘文件高性能读写

news2025/1/19 14:11:47

highlight: arduino-light

Broker读写磁盘文件的核心技术:mmap

Broker中大量的使用mmap技术去实现CommitLog这种大磁盘文件的高性能读写优化的。

通过之前的学习,我们知道了一点,就是Broker对磁盘文件的写入主要是借助直接写入os cache来实现性能优化的,因为直接写入os cache,相当于就是写入内存一样的性能,后续等os内核中的线程异步把cache中的数据刷入磁盘文件即可。

那么今天我们就要对这个过程中涉及到的mmap技术进行一定的分析。

1.传统文件IO:4次数据拷贝

首先我们先来给大家分析一下,假设RocketMQ没有使用mmap技术,就是使用最传统和基本的普通文件IO操作去进行磁盘文件的读写,那么会存在什么样的性能问题?

答案是:多次数据拷贝问题

首先,假设我们有一个程序,这个程序需要对磁盘文件发起IO操作读取他里面的数据到自己这儿来,那么会经过以下一个顺序:

首先从磁盘上把数据读取到内核IO缓冲区里去,然后再从内核IO缓存区里读取到用户进程私有空间里去,然后我们才能拿到这个文件里的数据。

image.png

为了读取磁盘文件里的数据,是不是发生了两次数据拷贝?

没错,所以这个就是普通的IO操作的一个弊端,必然涉及到两次数据拷贝操作,对磁盘读写性能是有影响的。

那么如果我们要将一些数据写入到磁盘文件里去呢?

那这个就是一样的过程了,必须先把数据写入到用户进程私有空间里去,然后从这里再进入内核IO缓冲区,最后进入磁盘文件里去

image.png

在数据进入磁盘文件的过程中,是不是再一次发生了两次数据拷贝?

没错,所以这就是传统普通IO的问题,有4次数据拷贝问题。

2.基于mmap+pageCache技术优化

mmap是什么

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.

对文件进行mmap后,会在进程的虚拟内存分配地址空间,创建与磁盘的映射关系。 实现这样的映射后,就可以以指针的方式读写操作映射的虚拟内存,系统则会自动回写磁盘;相反,内核空间对这段区域的修改也直接反映到用户空间,从而可以实现不同进程间的数据共享。与传统IO模式相比,减少了一次用户态copy到内核态的操作

mmap+write

mmap+write简单来说就是使用mmap替换了read+write中的read操作,减少了一次CPU的拷贝。

mmap主要实现方式是将读缓冲区的地址和用户缓冲区的地址进行映射,内核缓冲区和应用缓冲区共享,从而减少了从读缓冲区到用户缓冲区的一次CPU拷贝。

本来是read + write是4切4拷。

现在变成了1次映射 + 3次拷贝 + 4切

1.从磁盘通过DMA拷贝到内核缓存区 2.从内核映射到用户缓存区 3.写的时候直接基于内核缓存区写到socket缓冲区 4.再从socket缓冲区到网卡引擎

image.png

接着我们来看一下,RocketMQ如何利用mmap技术配合page cache技术进行文件读写优化的?

首先,RocketMQ底层对CommitLog、ConsumeQueue之类的磁盘文件的读写操作,基本上都会采用mmap技术来实现。

如果具体到代码层面,就是基于JDK NIO包下的MappedByteBuffer的map()函数,来将磁盘文件CommitLog文件,或者ConsumeQueue文件映射到内存里来

这里我必须给大家解释一下,这个所谓的内存映射是什么意思

其实有的人可能会误以为是直接把那些磁盘文件里的数据给读取到内存里来了,类似这个意思,但是并不完全是对的。

因为刚开始你建立映射的时候,并没有任何的数据拷贝操作,其实磁盘文件还是停留在那里,只不过他把物理上的磁盘文件的一些地址和用户进程私有空间的一些虚拟内存地址进行了一个映射

``` mmap 把文件映射到用户空间里的虚拟内存,省去了从内核缓冲区复制到用户空间的过程,文件中的位置在虚拟内存中有了对应的地址,可以像操作内存一样操作这个文件,这样的文件读写文件方式少了数据从内核缓存到用户空间的拷贝,效率很高。

第一步:mmap系统调用使得文件内容被DMA引擎复制到内核缓冲区。然后该缓冲区与用户进程共享,在内核和用户内存空间之间不进行任何拷贝。

第二步:写系统调用使得内核将数据从原来的内核缓冲区复制到与套接字相关的内核缓冲区。

第三步:第三次拷贝发生在DMA引擎将数据从内核套接字缓冲区传递给协议引擎时。

通过使用mmap而不是read,我们将内核需要拷贝的数据量减少了一半。当大量的数据被传输时,这将有很好的效果。 ```

image.png

这个地址映射的过程,就是JDK NIO包下的MappedByteBuffer.map()函数干的事情,底层就是基于mmap技术实现的。

另外这里给大家说明白的一点是,这个mmap技术在进行文件映射的时候,一般有大小限制,在1.5GB~2GB之间

所以RocketMQ才让CommitLog单个文件在1GB,ConsumeQueue文件在5.72MB,不会太大。

这样限制了RocketMQ底层文件的大小,就可以在进行文件读写的时候,很方便的进行内存映射了。

然后接下来要给大家讲的一个概念,就是之前给大家说的PageCache,实际上在这里就是对应于虚拟内存

所以我们在下面的图里就给大家画出了这个示意。 !

5e6349740001bedf04800304.jpg

mmap优点

1、对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。

2、实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。

3、提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。

同时,如果进程A和进程B都映射了区域C,当A第一次读取C时通过缺页从磁盘复制文件页到内存中;但当B再读C的相同页面时,虽然也会产生缺页异常,但是不再需要从磁盘中复制文件过来,而可直接使用已经保存在内存中的文件数据。

4、可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。换句话说,但凡是需要用磁盘空间代替内存的时候,mmap都可以发挥其功效。

相比磁盘空间,内存那么小,Mmap操作是不是很占用内存空间?

需要注意的是,进行Mmap映射时,并不是直接申请与磁盘文件一样大小的内存空间;而是使用进程的地址空间与磁盘文件地址进行映射,当真正的文件读取是当进程发起读或写操作时。

当进行IO操作时,发现用户空间内不存在对应数据页时(缺页),会先到交换缓存空间(swap cache)去读取,如果没有找到再去磁盘加载(调页)。

需要注意的是,进行Mmap映射时,并不是直接申请与磁盘文件一样大小的内存空间;而是使用进程的地址空间与磁盘文件地址进行映射,当真正的文件读取是当进程发起读或写操作时。

当进行IO操作时,发现用户空间内不存在对应数据页时(缺页),会先到交换缓存空间(swap cache)去读取,如果没有找到再去磁盘加载(调页)。

mmap有哪些应用场景?

进程间通信: 从自身属性来看,mmap具有提供进程间共享内存及相互通信的能力,各进程可以将自身用户空间映射到同一个文件的同一片区域,通过修改和感知映射区域,达到进程间通信和进程间共享的目的。

大数据高效存取: 对于需要管理或传输大量数据的场景,内存空间往往是不够用的,这时可以考虑使用Mmap进行高效的磁盘IO,弥补内存的不足。例如RocketMQ,MangoDB等主流中间件中都用到了Mmap技术;总之,但凡需要用磁盘空间替代内存空间的时候都可以考虑使用Mmap

参考:高效IO解决方案-mmap给你想要的快

基于mmap+pagecache实现高性能的文件读写

接下来就可以对这个已经映射到内存里的磁盘文件进行读写操作了,比如要写入消息到CommitLog文件,你先把一个CommitLog文件通过MappedByteBuffer的map()函数映射其地址到你的虚拟内存地址。

接着就可以对这个MappedByteBuffer执行写入操作了,写入的时候他会直接进入PageCache中,然后过一段时间之后,由os的线程异步刷入磁盘中,如下图我们可以看到这个示意。

image.png

看到这里我们有没有发现什么问题?

对了!就是上面的图里,似乎只有一次数据拷贝的过程,他就是从PageCache里拷贝到磁盘文件里而已!这个就是你使用mmap技术之后,相比于传统磁盘IO的一个性能优化。

接着如果我们要从磁盘文件里读取数据呢?

那么此时就会判断一下,当前你要读取的数据是否在PageCache里?

如果在的话,就可以直接从PageCache里读取了!

比如刚写入CommitLog的数据还在PageCache里,此时你Consumer来消费肯定是从PageCache里读取数据的。

但是如果PageCache里没有你要的数据,那么此时就会从磁盘文件里加载数据到PageCache中去,如下图

而且PageCache技术在加载数据的时候,还会将你加载的数据块的临近的其他数据块也一起加载到PageCache里去。

image.png

大家可以看到,在你读取数据的时候,其实也仅仅发生了一次拷贝,而不是两次拷贝,所以这个性能相较于传统IO来说,肯定又是提高了。

3.预映射机制 + 文件预热机制

接着给大家说几个Broker针对上述的磁盘文件高性能读写机制做的一些优化:

(1)内存预映射机制:Broker会针对磁盘上的各种CommitLog、ConsumeQueue文件预先分配好MappedFile,也就是提前对一些可能接下来要读写的磁盘文件,提前使用MappedByteBuffer执行map()函数完成映射,这样后续读写文件的时候,就可以直接执行了。

(2)文件预热:在提前对一些文件完成映射之后,因为映射不会直接将数据加载到内存里来,那么后续在读取尤其是CommitLog、ConsumeQueue的时候,其实有可能会频繁的从磁盘里加载数据到内存中去。

所以在执行完map()函数之后,会进行madvise系统调用,就是提前尽可能多的把磁盘文件加载到内存里去。

通过上述优化,才真正能实现一个效果,就是写磁盘文件的时候都是进入PageCache的,保证写入高性能;

同时尽可能多的通过map + madvise的映射后预热机制,把磁盘文件里的数据尽可能多的加载到PageCache里来,后续对CosumeQueue、CommitLog进行读取的时候,才能尽可能从内存里读取数据。

4.磁盘顺序读写

磁盘如果使用得当,磁盘的速度完全可以匹配上网络的数据传输速度。目前的高性能磁盘,顺序写速度可以达到600MB/s, 超过了一般网卡的传输速度。但是磁盘随机写的速度只有大概100KB/s,和顺序写的性能相差6000倍!

因为有如此巨大的速度差别,好的消息队列系统会比普通的消息队列系统速度快多个数量级。RocketMQ的消息用顺序写,保证了消息存储的速度。

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

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

相关文章

如何判断开发的商城系统是不是O2O平台?

纵观如今各大电商模式,数O2O发展最为火热,毫不夸张的说,O2O模式已经渗透到了很多行业中,那么哪些平台属于O2O呢?小编收集了一些资料,并将当下O2O平台分为以下这4种类型,下面小编就来带大家一起去了解了解!…

多模态系列论文--CoCa 详细解析

论文地址:CoCa: Contrastive Captioners are Image-Text Foundation Models 代码地址:CoCa CoCa 1 摘要2 网络结构3 损失函数4 实验结果5 总结 1 摘要 CoCa代表Contrastive Captioners的缩写,代表模型用两个目标函数训练出来的,一…

回溯法解决地图填色问题

目录 回溯法 最大度优先 最少可选颜色优先 向前探测 随机产生不同规模的图,分析算法效率与图规模的关系(四色) 回溯法 回溯法的基本思想是采用递归和深度优先搜索的方法,尝试在一组可能的解中搜索出符合要求的解&#xff0c…

Langchain的新课程;Mozilla开发的AI文档工具遭到开发者批评

🦉 AI新闻 🚀 Mozilla开发的AI文档工具遭到开发者批评,已下线 摘要:Mozilla开发的基于生成式AI的工具AI Help在开发者群体中遭到广泛批评。开发者认为该工具提供的信息常常错误,甚至认为它没有这个功能反而更好。针对…

Flutter 仿抖音、豆瓣、知乎、番茄小说的评论弹窗开发实践

最近用flutter做了一个评论弹窗的功能,本来以为很简单的烂大街的一个功能,结果却遇到了不少的问题,而且这些问题我觉得很有意义,以至于我觉得我如果分享出来可能会对其他人很有帮助。 要做一件事情可能会很容易,但做好…

ModaHub魔搭社区: AI模型社区ModelScope和Hugging Face行业分析报告

目录 引言: 一、github星数: 二、模型数: 三、数据集: 四、演示应用程序数: 五、下载数: 六、开发者、付费企业和公司用户数: 结论: 引言: AI模型开源社区在近年…

MQTT资料储备

1、官网 https://mqtt.org/ MQTT 5.0官方协议 https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html 说明:官网可以获取到好多资料(比如常用软件、协议、usecase等) 2、安装部署EMQX 当前有好多MQTT服务器,初步选择了EM…

MyBatis查询数据库【秘籍宝典】

0.MyBatis执行流程1.第一个MyBatis查询1.创建数据库和表1.2.添加MyBatis框架依赖【新项目】1.3.添加MyBatis框架依赖【旧项目】1.4.配置连接数据库1.5.配置MyBatis的XML路径2.MyBatis模式开发2.1 添加MyBatis的xml配置 3.增查改删(CRUD)5.1.增加操作5.2.…

机器学习之多元微积分

机器学习的多元微积分跟高等数学中的多元微积分有很多不同之处。 机器学习中的变量都是向量或者矩阵机器学习中的函数一般都是线性函数,而不是高数中的曲线和曲面、体积等函数。因此,机器学习中的微积分跟线性代数结合在一起。机器学习中导数的分子分母…

Chapter 4: Functions | Python for Everybody 讲义笔记_En

文章目录 Python for Everybody课程简介FunctionsFunction callsBuilt-in functionsType conversion functionsMath functionsRandom numbersAdding new functionsDefinitions and usesFlow of executionParameters and argumentsFruitful functions and void functionsWhy fun…

GEE:GEE上一些好看的可视化参数

作者:CSDN _养乐多_ 为了方便使用,总结了几种可视化参数。 文章目录 一、连续型1.11.21.31.41.5 二、离散型2.1 一、连续型 1.1 var phenoPalette [ff0000,ff8d00,fbff00,4aff00,00ffe7,01b8ff,0036ff,fb00ff]1.2 var evapotranspirationVis {min…

异地手机卡如何在当地办理宽带【纯教程篇】

有一些小伙伴常年在外漂泊会经常使用异地卡套餐,但是当你需要办理宽带业务的时候,很多时候当地的营业厅会让你再办理一张他们本地的手机卡,不方便不说还要多支付一张卡的月租也不划算。 其实呢运营商早就有异地办理宽带的业务,只不…

公司新来了个卷王,还是个00后,我们这帮老油条真干不过...

都说00后躺平了,但是有一说一,该卷的还是卷。这不,前段时间我们公司来了个00后,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 …

浅析集群、分布式、负载均衡

平时开发或者面试中进场听到集群、分布式、负载均衡等系列的名词,他们之间有什么联系呢,本文就简要的抛砖引玉一下。 集群 1.什么是集群 集群一般指的是服务器集群。集群其实就是一组相互独立的计算机,通过高速的网络组成一个计算机系统。…

深度学习笔记之Transformer(六)Position Embedding铺垫:Skipgram与CBOW模型

深度学习笔记之Transformer——PositionEmbedding铺垫:Skipgram与CBOW模型 引言回顾: Word2vec \text{Word2vec} Word2vec模型补充:关于 Word2vec \text{Word2vec} Word2vec的一些说明 引言 上一节介绍了 Word2vec \text{Word2vec} Word2vec…

【动态规划算法】第九题:64. 最小路径和

💖作者:小树苗渴望变成参天大树🎈 🎉作者宣言:认真写好每一篇博客💤 🎊作者gitee:gitee✨ 💞作者专栏:C语言,数据结构初阶,Linux,C 动态规划算法🎄 如 果 你…

Todo-List案例版本一

初级使用e.target.value 记得安装npm i nanoid与UUID类似 快捷键ctrlH替换内容 src/components/MyHeader.vue <template><div class"todo-header"><input type"text" placeholder"请输入你的任务名称&#xff0c;按回车键确认&quo…

express框架中使用ejs

1.设置模块引擎为ejs app.set("view engine","ejs") 2. 设置模版文件存放位置 说明&#xff1a;模版文件&#xff1a;具有模版语法内容的文件。 app.set(vies,path.resolve(__dirname,"./views")) 3.render渲染 app.get(/home,(req,res)>{/…

MySQL第三天(简单单表查询)

前言 今天的三个题目是针对于单表查询和多表查询的课后作业&#xff0c;针对于初学者还是很合适的听有用处的&#xff0c;我会把我的答题过程一步一步写出来&#xff0c;有需要的小伙伴可以参考哦… 第一题、单表信息查询 题目代码如下&#xff1a; 作业&#xff1a;1.创建表…

【计算机组成原理总结】

第一章计算机系统概述 第二章数据的表示与运算 第三章存储系统 第四章 指令系统 第五章 中央处理器 第六章 总线 第七章 输入输出设备