随着技术的不断进步,计算机的速度越来越快。但是磁盘IO速度往往让欲哭无泪,和内存中的读取速度有着指数级的差距;然而由于互联网的普及,网民数量不断增加,对系统的性能带来了巨大的挑战,系统性能往往是无数技术人不断追求的方向。

CPU,内存,IO三者之间速度差异很大。对于高并发,低延迟的系统来说,磁盘IO往往最先成为系统的瓶颈;为了减少其影响,往往会引入缓存来提升性能。但是由于内存空间有限,往往只能保存部分数据;并且数据需要持久化,所以磁盘IO仍然不可避免。

无论是从HDD(机械硬盘)到SSD(固态硬盘)的硬件提升;还是从BIO(阻塞IO)到 NIO(非阻塞IO)的软件上的提升;都使得磁盘IO效率得到了很大的提升,但是相比内存读取速度仍然有着接近巨大的差距。今天笔者将介绍一种更加高效的IO解决方案Mmap(内存映射文件,memory mapped file)

1. 用户态和内核态

为了安全,操作系统将虚拟内存划分为两个模块,即用户态和内核态。它们之间是相互隔离的,即使用户程序崩溃了也不会影响系统的运行。


用户态和内核态包含很多复杂的概念,在此不做过多介绍。简单来说,用户态是用户程序代码运行的地方,而内核态则是所有进程共享的空间。所以,当进行数据读写操作时,往往需要进行用户空间和内核空间的交互。

传统的IO模型进行磁盘数据读写时,一般大致需要2个步骤,拿写入数据为例:1.从用户空间拷贝到内核空间;2.从内核空间写入磁盘。


2. Mmap是什么

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

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


3. 性能测试

从实现原理上来看,我们可以大胆预测,Mmap的性能应该是优于传统IO。为了尽可能保证的数据的确性,笔者使用JMH工具对传统IO与Mmap的读和写进行基准测试。测试代码可到笔者github中获取。

需要注意的是,笔者的测试结果并不严谨,真实的差距要比以下结果要明显的多;原因在于,测试方法运行时间包含了文件的创建,内容初始化以及删除操作所需要的时间。以下是笔者电脑的测试结果「系统:macOS 处理器:2.6GHz 六核 i7 内存:16G 磁盘类型:SSD」

随机读性能测试


随机写性能测试


从读和写的结果报告中都不难看出,无论是读和写的结果印证了我们的猜想以及理论依据,Mmap的性能要远优于传统IO,而在Java中传统IO中的NIO又优于BIO。

4.Mmap在RocketMQ中的应用

RocketMQ是一个分布式消息和流平台,具有低延迟、高性能和可靠性、万亿级容量和灵活的可伸缩性。那么问题来了,对于海量消息的处理它是怎么保证高性能和可靠性的呢?

  1. RocketMQ的大致执行流程

RocketMQ中消息生产, 存储和消费流程大致可以分为以下几个流程:

  • 生产者发送消息到Broker「消息中转角色,负责存储,转发消息」
  • Broker中将消息存储在CommitLog中,并在对应的ConsumerQueue中写入消息的commitLogOffset,msgSize,tagCode等信息「消息在CommitLog中的位置,大小,以及标签信息」
  • 消费者从对应的ConsumerQueue中读取到消息的信息,根据消息的位置从CommitLog中读取消息体,然后进行消费

  1. RocketMQ中的Mmap

CommitLog是消息主体以及元数据的存储主体,存储Producer端写入的消息主体内容,消息内容是不定长的。单个CommitLog文件大小是固定的,默认1G ;文件名长度为20位,左边补零,剩余为起始偏移量,比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。消息主要是顺序写入日志文件,当文件满了,写入下一个文件。

消息存储在CommitLog文件中,每个消费者消费消息时,都是根据消息在文件中偏移量, 大小去读取消息。读取消息的过程伴随着随机访问读取,严重影响性能。RocketMQ主要通过Mmap技术对CommitLog文件进行读写,将对文件的操作转化为直接对内存地址进行操作,从而极大地提高了文件的读写效率。


正因为需要使用内存映射机制,故RocketMQ的文件存储都使用定长结构来存储,方便一次将整个文件映射至内存

5.Q&A

  1. Mmap为什么那么快?

使用Mmap对文件的读写操作跨过内核空间,减少1次数据的拷贝,进而提高了文件IO效率。

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

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

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

  1. Mmap有哪些应用场景?

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

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

  1. Mmap有什么缺点?

内存映射文件需要在进程的占用一块很大的连续逻辑地址空间。对于Intel的IA-32的4GB逻辑地址空间,可用的连续地址空间远远小于2---3 GiB。

一旦使用内存关联文件,在程序运行期间,程序的执行可能受关联文件的错误影响。相关联的文件的I/O错误(如可拔出驱动器或光驱被弹出,磁盘满时写操作等)的内存映射文件会向应用程序报异常;而通常的内存操作是无需考虑这些异常的。

有内存管理单元(MMU)才支持内存映射文件。


img

高效IO解决方案-Mmap「给你想要的快」的更多相关文章

  1. 如何评价苹果中国官网 iOS 8 介绍页面的文案「开发者的大事、大快所有人心的大好事」?[转自知乎]

    在什么是「苹果式中文」答案中,小七得出了这个结论: 「苹果式中文」是指句子结构破碎,经常缺乏主语,滥用排比,顶真,偏正短语,和不恰当四字词的广告文体. (有关什么是苹果式中文,小七原来贴错地方了TAT ...

  2. 【LOJ6077】「2017 山东一轮集训 Day7」逆序对 生成函数+组合数+DP

    [LOJ6077]「2017 山东一轮集训 Day7」逆序对 题目描述 给定 n,k ,请求出长度为 n的逆序对数恰好为 k 的排列的个数.答案对 109+7 取模. 对于一个长度为 n 的排列 p ...

  3. 「newbee-mall新蜂商城开源啦」GitHub 上最热门的 Spring Boot 项目,我也要做一次靓仔!

    没有一个冬天不可逾越,也没有一个春天不会到来. 介绍一下新蜂商城的近况,同时,新蜂商城 Vue 版本目前也在开发中,在这篇文章里我也向大家公布一下新蜂商城 Vue 版本的开发进度,和大家同步一下,在不 ...

  4. 「newbee-mall新蜂商城开源啦」 前后端分离的 Vue 版本即将开源

    新蜂商城 Vue 版本 2019 年 10 月份我在 GitHub 开源仓库中上传了新蜂商城项目的所有源码,至今已经有小半年的时间了,感兴趣的可以去了解一下这个 Spring Boot 技术栈开发的商 ...

  5. SSH连接时出现「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」解决办法

    用ssh來操控github,沒想到連線時,出現「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」,後面還有一大串英文,這時當然要向Google大神求助 ...

  6. 「ZJOI2019」&「十二省联考 2019」题解索引

    「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...

  7. Loj #6069. 「2017 山东一轮集训 Day4」塔

    Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...

  8. Loj #6073.「2017 山东一轮集训 Day5」距离

    Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...

  9. Loj 6068. 「2017 山东一轮集训 Day4」棋盘

    Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...

随机推荐

  1. PDO::getAttribute

    PDO::getAttribute — 取回一个数据库连接的属性(PHP 5 >= 5.1.0, PECL pdo >= 0.1.0) 说明 语法 mixed PDO::getAttrib ...

  2. Skill 计算两点距离

    https://www.cnblogs.com/yeungchie/ code procedure(ycHowFar(a b) prog((xAB yAB sAB) xAB = xCoord(a) - ...

  3. CF 633 div1 1338 B. Edge Weight Assignment 构造

    LINK:Edge Weight Assignment 这场当时没打 看到这个B题吓到我了 还好当时没打. 想了20min才知道怎么做 而且还不能证明. 首先考虑求最小. 可以发现 如果任意两个叶子节 ...

  4. E CF R 85 div2 1334E. Divisor Paths

    LINK:Divisor Paths 考试的时候已经想到结论了 可是质因数分解想法错了 导致自闭. 一张图 一共有D个节点 每个节点x会向y连边 当且仅当y|x,x/y是一个质数. 设f(d)表示d的 ...

  5. 不使用spring-boot-starter-parent作为依赖parent

    背景环境 在某些情况下由于某些原因,我们的项目不能使用spring-boot-starter-parent作为<parent>依赖,一定要有自己的<parent>,但同时还希望 ...

  6. JAVA 连接 ZooKeeper之初体验

    Java连接Zookeeper 一.配置zk环境 本人使用的是虚拟机,创建了两台linux服务器(安装过程百度上很多) 准备zk的安装包,zookeeper-3.4.10.tar.gz,可在Apach ...

  7. webMvcConfigurer的详情

                  摘要 Spring的WebMvcConfigurer接口提供了很多方法让我们来定制SpringMVC的配置.而且Spring还提供了WebMvcConfigurerAdap ...

  8. GitLab 配置模板

    GitLab 配置模板 GitLab 使用模板和参数生成配置文件. 一般来说,我们会通过 gitlab.rb 文件修改配置,例如 Nginx 相关配置. gitlab.rb 只能使用特定的几个 Ngi ...

  9. mongodb 4.0副本集搭建

    近期有同学问mongodb副本集难不难部署,我的回答是不难,很快,几分钟搞定,比mysql MHA简单的不止一点半点. 那么到底如何部署呢?请看下文. 1.  准备工作 1.1 下载软件 选择版本并下 ...

  10. .NET 跨平台框架Avalonia UI: 填坑指北(一):熟悉UI操作

    Avalonia 是一个跨平台的 .NET UI 框架,支持 Windows.Linux.Mac OSX... (以及Android  IOS soon..) 本篇主要介绍Avalonia开发过程和L ...