漫谈linux之文件IO篇(SSD写性能和机械硬盘差不多,读是4到10倍)
前同事的文章,觉得写得很清晰,收藏了。
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写性能和机械硬盘差不多。
https://blog.csdn.net/hairetz/article/details/18704783
漫谈linux之文件IO篇(SSD写性能和机械硬盘差不多,读是4到10倍)的更多相关文章
- linux中文件IO
一. linux常用文件IO接口 1.1. 文件描述符 1.1.1. 文件描述符的本质是一个数字,这个数字本质上是进程表中文件描述符表的一个表项,进程通过文件描述符作为index去索引查表得到文件表指 ...
- Linux 查看文件被那个进程写数据
目录 背景 步骤 获取写文件的进程号 文件被那个进程使用,写数据不是用lsof可以找出来吗,但现实情况是lsof没找出来T_T 背景 centos7 在某一段时间监控报警磁盘使用率达99%,由于监控属 ...
- Linux C 文件IO
文件IO 2021-05-31 12:46:14 星期一 目录 文件IO 基础IO open 错误 creat read 一个例子 write close lseek 文件空洞 unlink删除 io ...
- linux下 文件IO 相关
linux下操作文件或设备,需要一个文件描述符 file descriptor,fd 来引用.fd是一个非负整数,实际上是一个索引值,指向文件的记录表,对文件的操作都需要fd.默认的几个:标准输入流 ...
- 【Linux】文件IO --- sync、fsync、fdatesync
在使用write函数向文件中写入数据的时候,并不是在调用了函数以后就直接把数据写入磁盘:操作系统在内核中设置了一块专门的缓冲区,数据会先被写入到内核的缓冲区中,等到缓冲区满了或者系统需要重新利用缓冲区 ...
- 转 漫谈linux文件IO
在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用 ...
- 漫谈linux文件IO
在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用 ...
- 【转】漫谈linux文件IO--io流程讲的很清楚
[转]漫谈linux文件IO--io流程讲的很清楚 这篇文章写的比较全面,也浅显易懂,备份下.转载自:http://blog.chinaunix.net/uid-27105712-id-3270102 ...
- <摘录>linux文件IO
这篇文章写的比较全面,也浅显易懂,备份下.转载自:http://blog.chinaunix.net/uid-27105712-id-3270102.html 在Linux 开发中,有几个关系到性能的 ...
随机推荐
- PHP中对hmac_sha1签名算法的实现方法
最近研究网宿云文档API,其中用到了一种叫hmac_sha1的签名算法: HMAC-SHA1: HMAC是哈希运算消息认证码 (Hash-based Message Authentication Co ...
- 一个通用Makefile的编写
作者:杨老师,华清远见嵌入式学院讲师. 我们在Linux环境下开发程序,少不了要自己编写Makefile,一个稍微大一些的工程下面都会包含很多.c的源文件.如果我们用gcc去一个一个编译每一个源文件的 ...
- POJ 2773
不经意看见dis后的“mod”一词后,瞬间有了思路,点进去看,却发现别人想的和我的不一样——! 我是这样想的,利用的是剩余系+欧几里德带余除法的性质. 若两者GCD=1,则必有除数和余数GCD=1.于 ...
- php抽奖、随机广告算法
我们先完毕后台PHP的流程,PHP的主要工作是负责配置奖项及相应的中奖概率,当前端页面点击翻动某个方块时会想后台PHP发送ajax请求,那么后台PHP依据配置的概率,通过概率算法给出中奖结果,同一时候 ...
- (转)<![CDATA[]]>和转义字符
被<![CDATA[]]>这个标记所包含的内容将表示为纯文本,比如<![CDATA[<]]>表示文本内容“<”. 此标记用于xml文档中,我们先来看看使用转义符的情 ...
- c3p0在spring中的配置
在大家的开发和学习其中应该经经常使用到数据库的连接和使用,只是连接 的方式就有非常多种方式了,例如说用最最简单的JDBC 也好,还实用比 较复杂一点的就是数据库连接池.当然还有使用DBCP的连接的,各 ...
- JavaScript-4.4函数递归之阶乘举例---ShinePans
<html> <head> <meta http-equiv="content-type" content="text/html;chars ...
- How to Hide Zip Files Inside a Picture Without any Extra Software in Windows
http://www.howtogeek.com/119365/how-to-hide-zip-files-inside-a-picture-without-any-extra-software/ c ...
- iOS开发-Tools-CocoaPods
CocoaPods是什么? 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而 ...
- VS 2015 C#不能进入断点
工程\属性\生成页面,去掉优化代码勾选.