MMAP和DIRECT IO区别【转】

简介: 转自:http://www.cnblogs.com/zhaoyl/p/5901680.html 看完此文,题目不言自明。转自 http://blog.chinaunix.net/uid-27105712-id-3270102.html 在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO。

转自:http://www.cnblogs.com/zhaoyl/p/5901680.html

看完此文,题目不言自明。转自 http://blog.chinaunix.net/uid-27105712-id-3270102.html

在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO。本篇文件打算详细全面,深入浅出。剖析文件IO的细节。从多个角度探索如何提高IO性能。本文尽量用通俗易懂的视角去阐述。不copy内核代码。

 

    阐述之前,要先有个大视角,让我们站在万米高空,鸟瞰我们的文件IO,它们设计是分层的,分层有2个好处,一是架构清晰,二是解耦。让我们看一下下面这张图。

1.       穿越各层写文件方式

程序的最终目的是要把数据写到磁盘上, 但是系统从通用性和性能角度,尽量提供一个折中的方案来保证这些。让我们来看一个最常用的写文件典型example,也是路径最长的IO。

{

    char *buf = malloc(MAX_BUF_SIZE);

    strncpy(buf, src, , MAX_BUF_SIZE);

     fwrite(buf, MAX_BUF_SIZE, 1, fp);

     fclose(fp);

 }

  

这里malloc的buf对于图层中的application buffer,即应用程序的buffer;调用fwrite后,把数据从application buffer 拷贝到了 CLib buffer,即C库标准IObuffer。fwrite返回后,数据还在CLib buffer,如果这时候进程core掉。这些数据会丢失。没有写到磁盘介质上。当调用fclose的时候,fclose调用会把这些数据刷新到磁盘介质上。除了fclose方法外,还有一个主动刷新操作fflush 函数,不过fflush函数只是把数据从CLib buffer 拷贝到page  cache 中,并没有刷新到磁盘上,从page cache刷新到磁盘上可以通过调用fsync函数完成。 

从上面类子看到,一个常用的fwrite函数过程,基本上历经千辛万苦,数据经过多次copy,才到达目的地。有人心生疑问,这样会提高性能吗,反而会降低性能吧。这个问题先放一放。

 

有人说,我不想通过fwrite+fflush这样组合,我想直接写到page cache。这就是我们常见的文件IO调用read/write函数。这些函数基本上是一个函数对应着一个系统调用,如sys_read/sys_write. 调用write函数,是直接通过系统调用把数据从应用层拷贝到内核层,从application buffer 拷贝到 page cache 中。

 系统调用,write会触发用户态/内核态切换?是的。那有没有办法避免这些消耗。这时候该mmap出场了,mmap把page cache 地址空间映射到用户空间,应用程序像操作应用层内存一样,写文件。省去了系统调用开销。

 那如果继续刨根问底,如果想绕过page cache,直接把数据送到磁盘设备上怎么办。通过open文件带上O_DIRECT参数,这是write该文件。就是直接写到设备上。

 

如果继续较劲,直接写扇区有没有办法。这就是所谓的RAW设备写,绕开了文件系统,直接写扇区,想fdsik,dd,cpio之类的工具就是这一类操作。

  

2.       IO调用链

列举了上述各种穿透各种cache 层写操作,可以看到系统提供的接口相当丰富,满足你各种写要求。下面通过讲解图一,了解一下文件IO的调用链。

 fwrite是系统提供的最上层接口,也是最常用的接口。它在用户进程空间开辟一个buffer,将多次小数据量相邻写操作先缓存起来,合并,最终调用write函数一次性写入(或者将大块数据分解多次write调用)。 

Write函数通过调用系统调用接口,将数据从应用层copy到内核层,所以write会触发内核态/用户态切换。当数据到达page cache后,内核并不会立即把数据往下传递。而是返回用户空间。数据什么时候写入硬盘,有内核IO调度决定,所以write是一个异步调用。这一点和read不同,read调用是先检查page cache里面是否有数据,如果有,就取出来返回用户,如果没有,就同步传递下去并等待有数据,再返回用户,所以read是一个同步过程。当然你也可以把write的异步过程改成同步过程,就是在open文件的时候带上O_SYNC标记。

 

数据到了page cache后,内核有pdflush线程在不停的检测脏页,判断是否要写回到磁盘中。把需要写回的页提交到IO队列——即IO调度队列。又IO调度队列调度策略调度何时写回。

提到IO调度队列,不得不提一下磁盘结构。这里要讲一下,磁头和电梯一样,尽量走到头再回来,避免来回抢占是跑,磁盘也是单向旋转,不会反复逆时针顺时针转的。从网上copy一个图下来,具体这里就不介绍。

 IO队列有2个主要任务。一是合并相邻扇区的,而是排序。合并相信很容易理解,排序就是尽量按照磁盘选择方向和磁头前进方向排序。因为磁头寻道时间是和昂贵的。

这里IO队列和我们常用的分析工具IOStat关系密切。IOStat中rrqm/s wrqm/s表示读写合并个数。avgqu-sz表示平均队列长度。

 

内核中有多种IO调度算法。当硬盘是SSD时候,没有什么磁道磁头,人家是随机读写的,加上这些调度算法反而画蛇添足。OK,刚好有个调度算法叫noop调度算法,就是什么都不错(合并是做了)。刚好可以用来配置SSD硬盘的系统。

 从IO队列出来后,就到了驱动层(当然内核中有更多的细分层,这里忽略掉),驱动层通过DMA,将数据写入磁盘cache。 

至于磁盘cache时候写入磁盘介质,那是磁盘控制器自己的事情。如果想要睡个安慰觉,确认要写到磁盘介质上。就调用fsync函数吧。可以确定写到磁盘上了。 

 

3.       一致性和安全性

谈完调用细节,再将一下一致性问题和安全问题。既然数据没有到到磁盘介质前,可能处在不同的物理内存cache中,那么如果出现进程死机,内核死,掉电这样事件发生。数据会丢失吗。

 当进程死机后:只有数据还处在application cache或CLib cache时候,数据会丢失。数据到了page cache。进程core掉,即使数据还没有到硬盘。数据也不会丢失。

 当内核core掉后,只要数据没有到达disk cache,数据都会丢失。 

掉电情况呢,哈哈,这时候神也救不了你,哭吧。

 

那么一致性呢,如果两个进程或线程同时写,会写乱吗?或A进程写,B进程读,会写脏吗?

  

文章写到这里,写得太长了,就举出各种各样的例子。讲一下大概判断原则吧。fwrite操作的buffer是在进程私有空间,两个线程读写,肯定需要锁保护的。如果进程,各有各的地址空间。是否要加锁,看应用场景。

write操作如果写大小小于PIPE_BUF(一般是4096),是原子操作,能保证两个进程“AAA”,“BBB”写操作,不会出现“ABAABB”这样的数据交错。O_APPEND 标志能保证每次重新计算pos,写到文件尾的原子性。

数据到了内核层后,内核会加锁,会保证一致性的。

4.       性能问题

性能从系统层面和设备层面去分析;磁盘的物理特性从根本上决定了性能。IO的调度策略,系统调用也是致命杀手。

磁盘的寻道时间是相当的慢,平均寻道时间大概是在10ms,也就是是每秒只能100-200次寻道。

磁盘转速也是影响性能的关键,目前最快15000rpm,大概就每秒500转,满打满算,就让磁头不寻道,设想所有的数据连续存放在一个柱面上。大家可以算一下每秒最多可以读多少数据。当然这个是理论值。一般情况下,盘片转太快,磁头感应跟不上,所以需要转几圈才能完全读出磁道内容。

  

另外设备接口总线传输率是实际速率的上限。

另外有些等密度磁盘,磁盘外围磁道扇区多,线速度快,如果频繁操作的数据放在外围扇区,也能提高性能。

利用多磁盘并发操作,也不失为提高性能的手段。

这里给个业界经验值:机械硬盘顺序写~30MB,顺序读取速率一般~50MB好的可以达到100多M, SSD读达到~400MB,SSD写性能和机械硬盘差不多。 

 

O_DIRECT  RAW设备最根本的区别是O_DIRECT是基于文件系统的,也就是在应用层来看,其操作对象是文件句柄,内核和文件层来看,其操作是基于inode和数据块,这些概念都是和ext2/3的文件系统相关,写到磁盘上最终是ext3文件。 

RAW设备写是没有文件系统概念,操作的是扇区号,操作对象是扇区,写出来的东西不一定是ext3文件(如果按照ext3规则写就是ext3文件)。 

一般基于O_DIRECT来设计优化自己的文件模块,是不满系统的cache和调度策略,自己在应用层实现这些,来制定自己特有的业务特色文件读写。但是写出来的东西是ext3文件,该磁盘卸下来,mount到其他任何linux系统上,都可以查看。 

而基于RAW设备的设计系统,一般是不满现有ext3的诸多缺陷,设计自己的文件系统。自己设计文件布局和索引方式。举个极端例子:把整个磁盘做一个文件来写,不要索引。这样没有inode限制,没有文件大小限制,磁盘有多大,文件就能多大。这样的磁盘卸下来,mount到其他linux系统上,是无法识别其数据的。 

两者都要通过驱动层读写;在系统引导启动,还处于实模式的时候,可以通过bios接口读写raw设备。

 

《直接io的优缺点》https://www.ibm.com/developerworks/cn/linux/l-cn-directio/

《aio和direct io关系以及DMA》http://blog.csdn.net/brucexu1978/article/details/7085924

《io模型矩阵》http://www.ibm.com/developerworks/cn/linux/l-async/

 

《为什么nginx引入多线程:减少阻塞IO影响》http://www.aikaiyuan.com/10228.html

《aio机制在nginx之中的使用:output chain 》http://www.aikaiyuan.com/8867.html

《nginx对Linux native AIO机制的封装》http://www.aikaiyuan.com/8869.html

 

《nginx output chain 分析》https://my.oschina.net/astute/blog/316954

《sendfile和read/write的内核切换次数》http://www.cnblogs.com/zfyouxi/p/4196170.html

【作者】 张昺华
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
目录
相关文章
|
存储 项目管理 Python
数据导入与预处理-第4章-数据获取python读取docx文档(上)
数据导入与预处理-第4章-pandas数据获取docx文档 1.python读取docx文档概述 1.1 从Word文件获取数据 1.2 python-docx库介绍 1. Paragraph类 2. Table类
数据导入与预处理-第4章-数据获取python读取docx文档(上)
|
网络协议 安全 Shell
如何在 SSH 客户端中强制使用 IPv4 或 IPv6?
如何在 SSH 客户端中强制使用 IPv4 或 IPv6?
2030 0
如何在 SSH 客户端中强制使用 IPv4 或 IPv6?
|
监控 druid Java
Spring Boot 3 集成 Druid 连接池详解
在现代的Java应用中,使用一个高效可靠的数据源是至关重要的。Druid连接池作为一款强大的数据库连接池,提供了丰富的监控和管理功能,成为很多Java项目的首选。本文将详细介绍如何在Spring Boot 3项目中配置数据源,集成Druid连接池,以实现更高效的数据库连接管理。
10266 2
Spring Boot 3 集成 Druid 连接池详解
|
安全 Linux 数据安全/隐私保护
Intel TME和MKTME技术解析
# 市场需求 人们对透明全内存加密这个功能的需求主要来自对机密和敏感数据的保护。普通RAM里面储存的数据,在掉电之后,一般都以为是彻底消失了。但其实在一些复杂的离线攻击下,这些数据仍然是能被恢复出来并导致泄密;而持久性存储器(即外存,包括磁盘、SSD、eMMC等)的数据更加容易泄露。这些设备可能有硬件锁机制的保护,但是用户其实希望的是更细粒度的保护,比如per进程/容器/VM级的。 Int
5869 0
Intel TME和MKTME技术解析
|
安全 虚拟化
虚拟化底层技术之——iommu技术综述
一、iommu 主要功能 IOMMU(i/o memory management unit)。iommu有两大功能:控制设备dma地址映射到机器物理地址(dmar),中断重映射(intremap)(可选) 1.1 dma地址空间映射 Iommu 的主要功能为设备dma时刻能够访问机器的物理内存区,同时保证安全性。
5625 0
|
11月前
|
敏捷开发 数据可视化 项目管理
燃起图是什么? 敏捷项目管理中不可忽视的高效利器
在现代项目管理中,团队效率至关重要。燃起图(Burn Up Chart)作为一种直观的可视化工具,通过展示完成工作量和总工作量的变化,帮助团队实时跟踪进度、应对需求变更,提高透明度与沟通效率。本文介绍了燃起图的功能、优势及应用方法,并推荐了几款支持燃起图的项目管理工具。
454 13
|
Ubuntu 网络安全 图形学
Ubuntu学习笔记(二):ubuntu20.04解决右上角网络图标激活失败或者消失,无法连接有线问题。
在Ubuntu 20.04系统中解决网络图标消失和无法连接有线网络问题的方法,其中第三种方法通过检查并确保Windows防火墙中相关服务开启后成功恢复了网络连接。
4444 0
Ubuntu学习笔记(二):ubuntu20.04解决右上角网络图标激活失败或者消失,无法连接有线问题。
|
存储 数据库 开发者
Elasticsearch中的三种分页策略深度解析:原理、使用及对比
Elasticsearch中的三种分页策略深度解析:原理、使用及对比
|
存储 芯片
键盘驱动程序设计
键盘驱动程序设计
293 0
|
存储 缓存 算法
分层存储结构
什么是分层存储 分层存储其实已经不是一个新鲜的概念,而是已经在计算机存储领域应用多年。其与计算机的发明与发展相伴相生。在冯-诺依曼提出计算机的模型“存储程序”时就已经包含了分层存储的概念。
2140 0