在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写性能和机械硬盘差不多。

Linux io操作相关推荐

  1. Linux IO操作——RIO包

    1.linux基本I/O接口介绍 ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, void *buf, siz ...

  2. linux的文件io操作(转)

    linux文件IO操作有两套大类的操作方式:不带缓存的文件IO操作,带缓存的文件IO操作.不带缓存的属于直接调用系统调用(system call)的方式,高效完成文件输入输出.它以文件标识符(整型)作 ...

  3. linux系统IO操作

    本文重点说明下面内容: 什么是标准IO,什么是文件IO? 什么是Direct IO? O_SYNC标识有什么意义? 各个层面的缓存如何同步? 还在page cache中的脏页可以读写吗? IO路径上的 ...

  4. Linux基础(6)--文件IO操作

    文件IO操作 1. open打开操作 2. close关闭操作 3. creat创建操作 4. write写操作 5. read读操作 Linux下一切皆文件,所以文件IO是很重要的也是很基础的操作. ...

  5. Linux下 C语言文件IO操作(系统IO)

    Linux系统下使用C语言进行文件系统IO操作 1打开文件 函数:int open(const char *,int flags); //打开一个已经存在的文件 int open(const char ...

  6. 嵌入式 Linux 文件IO操作

    目录 Linux 文件操作 1 Linux 系统环境文件操作概念 2 缓冲 IO 文件操作 1 文件的创建,打开与关闭 fopen 函数函数 2 freopen 函数 3.fdopen函数 4.fcl ...

  7. linux系统io错误,linux系统IO操作

    本文重点说明下面内容: 什么是标准IO,什么是文件IO? 什么是Direct IO? O_SYNC标识有什么意义? 各个层面的缓存如何同步? 还在page cache中的脏页可以读写吗? IO路径上的 ...

  8. 浅析Linux IO

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:0xffffff.org/ 写在前面 在开始正式的讨论前,我 ...

  9. [零基础学JAVA]Java SE应用部分-27.Java IO操作(01)

    JAVA IO操作目标 本季知识点 1.File类 2.RandomAccessFile类 File类 在JAVA中所有的IO操作全部存放在java.io包中. File是唯一一个与文件本身有关的操作 ...

最新文章

  1. 数组排序思想———选择排序
  2. 困难动态规划系列、经典的正则表达式和通配符匹配问题(难题)
  3. MVC教程第六篇:拦截器
  4. 简单工厂模式(静态工厂模式)
  5. 关于BinaryFormatter
  6. 关于SOA的应用研究思考
  7. 编译thrift和使用 - 翱翔云颠的博客 - 我的搜狐
  8. sap 设置服务器信息,服务器上配置sap
  9. SD卡、TF卡、MMC卡以及eMMC芯片的介绍
  10. 数仓第6篇:大数据可视化BI工具
  11. vue项目中实现汉字转拼音缩写
  12. 一款简洁的导航网源码
  13. 在fastreport里转换金额大小写
  14. 实验吧决斗场刷新刷新快刷新
  15. vm fusion Linux系统克隆
  16. iOS生态链寄生数百万开发者:艰难求生面临决择
  17. RV 多样式 MultiType 聊天界面 消息类型 MD
  18. ansys仿真论文描述
  19. AR9331标准电路设计归纳
  20. 《石碏大义灭亲(隐公三年、四年)》

热门文章

  1. 连面包店都在用NetSuite了,你还在等什么?
  2. churn rate 流失率
  3. 过敏性鼻炎与感冒症状区别
  4. 修改el-input样式
  5. 百元内的金牛座脑波模块带你玩转脑电波 可开发玩具
  6. EF实体中的数据修改更新
  7. 宗教信仰解题报告(c++)
  8. 解机器码LOL-CF,无视机器码虚拟机
  9. Android开发图标素材下载
  10. Java常见类库与工具及官网