http://blog.csdn.net/xypzwl/article/details/51416883

一、存储设备的存储原理

机械硬盘:

机械硬盘使用磁性物质作为存储介质,用N、S极性来代表0或1;

以无磁性的盘片作为基片(一般材质为铝合金或者玻璃),磁性物质在盘片上以同心圆的方式排列,这些同心圆的圆周被称为磁道;

磁道又被细分成一个个扇区,作为读写的最小单位(即就算需要读写的数据小于一个扇区,硬盘在实际读写时也会读取一个扇区的数据)。一般一个扇区的大小为512字节(1.非固定,现在也有4K大小的扇区;2.也叫做物理扇区,由硬盘的物理结构决定,无法更改);每个扇区都有一个从1开始的唯一的编号。

数据的读写是有磁头来进行的,硬盘使用时,盘片在高速旋转而磁头保持不动,由磁盘控制器控制磁头的半径依次遍历所有的扇区,从而达到读写数据的功能;

例:

假设硬盘有十个磁道,每次磁道上有十个扇区;现在需要读取第五磁道的第五扇区上的数据:

Step1.外部设备告知磁盘控制器数据的位置,第五磁道第五扇区;磁头由磁盘控制器控制半径大小从第1磁道开始依次经由第2、3、4磁道,最终到达第五磁道;

Step2.磁头保持半径不动,等待第五扇区旋转到磁头下方;

Step3.第五扇区已经到达磁头下方了,磁头开始读取第五扇区内的数据;并将数据发送给外部设备;

固态硬盘(SSD):

不了解,以后补充

U盘(flash存储设备):

不了解,以后补充

IO写入的代码表示:

  1. #define SECTOR_SIZE     //物理扇区大小,常见为512B,也有4KB的
  2. #define TOTAL_SIZE      //硬盘的总大小
  3. int Disk_write(int offset, void *data, int size)
  4. {
  5. static int pos = 0;
  6. int count = 0;
  7. int ret = -1;
  8. int startOffset, remain;
  9. char buf[SECTOR_SIZE] = {0};
  10. while(1)
  11. {
  12. startOffset = offset / SECTOR_SIZE;
  13. remain = offset % SECTOR_SIZE;
  14. if (startOffset == pos)
  15. {
  16. memcpy(buf + remain, data + count, MIN(SECTOR_SIZE - remain, size - count));
  17. count += MIN(SECTOR_SIZE - remain, size - count);
  18. offset += SECTOR_SIZE - remain;
  19. ret = write(buf, SECTOR_SIZE);  //是SECTOR_SIZE没错,每次写入一定是整数个扇区
  20. if (ret < 0 || count >= size)
  21. {
  22. return count;
  23. }
  24. }
  25. pos += SECTOR_SIZE;
  26. pos %= TOTAL_SIZE;
  27. sleep(10);  //表示寻道/写惩罚消耗的时间
  28. }
  29. }

二、IO流程:

这里针对的是基于操作系统之上的应用程序的I/O流程。大致的I/O流程如下图:

如上图显示,往硬盘写数据需要经过四个过程:

Step1: 应用程序发起IO调用(如fwrite/fread),要写入的数据被复制到应用层缓冲区中,在应用层缓冲区中数据会被重新组合,使得传递给下一步的数据是对齐的。(这一步的操作时非必需的,当调用库函数fwrite/fread时,会有这一层的缓冲,但如果是直接调用的系统函数write/read,将直接跳到下一步)

Step2:系统由用户态切换到系统态,数据被写入到系统缓冲区,这一步完成后write函数就认为写操作已经完成了,返回写数据结果(选择同步IO除外,选择同步IO的话会等到step4完成后才会返回)。

Step3:系统缓冲区内的数据被复制到操作系统page里面进行进一步的组合

Step4:数据被写入到硬盘的cache中,等待合适的时机将数据写到硬盘的指定位置;

Step5:硬盘的磁头到达指定的位置,将数据写入到硬盘中;只有当这一步完成时,数据才是真正的被保存下去了,如果在这一步完成之前出现异常,数据将会丢失。

在整个写数据流程中,之所以需要这么多的缓冲和数据复制,其原因是1.硬盘的读写速度相较于cpu的计算速度来说太慢了,需要缓冲区来缓冲数据,保证数据不会丢失;2.加快硬盘写入速度,通过这些缓冲,可以对应用层的读写操作进行优化合并,以减少不必要的读写操作,从而加快速度;

三、I/O优化:

I/O的最大瓶颈在于往存储设备里真正写数据的时候(上面I/O流程中的step4),这也是为什么应用数据进行I/O要经过多重缓冲的原因;

回顾下存储设备IO的流程:

1.      将磁头移到到指定的磁道(寻道);

2.      等待指定的扇区转到磁头下方(等待);

3.      真实IO操作;

(注:这是机械硬盘的流程,SSD和U盘没有寻道操作)

实际IO的速度有存储设备本身物理特性决定的,无法优化;但我们可以优化寻道和等待的时间(最理想的情况下是硬盘不需要寻道,也不需要等待),我们可以通过以下操作降低寻道和等待消耗的时间:

1.      按顺序读取数据;这样就不需要寻道和等待了。

2.      数据尽可能一次性读写,减少文件碎片;文件碎片就是一个文件在存储设备上存放时不是连续存放的,假设一个文件2K大小,可能它的前512字节存放在扇区1,第二个512字节存放在扇区10,最后1K存放在扇区5。这样虽然在逻辑上读取文件时没有seek操作,但实际上IO时还是需要等待的。

大部分的文件系统是先到先得的原则,因此一次性写入可以极大的降低文件碎片的情况。

3.      字节对齐;硬盘IO的最小单位为扇区,即使需要IO的数据小于一个扇区,实际IO时也是对一个扇区进行操作的。eg:假设一个扇区为512字节,现在需要分两次一共写入1K的数据,这1K数据存放在两个连续的扇区,扇区1和扇区2中。

(1)如果每次写512字节,整个IO消耗的时间就是两次真实IO的时间;

(2)而如果不对齐写,第一次写511个字节,第二次写513个字节;由于硬盘一次必须写入512字节,因此第一次IO时扇区1中写入了512字节,最后一个字节是无效数据,第二次IO时磁头已经偏移到扇区2了,但控制器发现第512个字节是在扇区1里面的,所以控制器会等到扇区1再次出现在磁头下面后才开始第二次IO,并且这次IO实际上只有一个字节是有效的;写完后还需要对扇区2再进行一次IO操作。因此整个IO消耗的时间等于三次真实IO的时间加上等待盘片转完一遍的时间(U盘的话还存在一个写惩罚,即每次IO时都要先将原来的数据读取出来,然后擦除数据,最后再将新数据写入进去,这也需要时间)

IO过程中,数据在这些缓冲区内进行复制也要消耗时间和性能的,字节对齐后,这些复制操作可视情况去掉(通过open时传入的参数进行修改),这里又可以节省点时间

4.      减少不必要的IO同步操作;一般IO时,操作系统、磁盘控制器等都会对传下来的数据进行优化,比如将多次write合并成一次,调整IO顺序,数据对齐等操作;而IO同步时不经过这些优化操作,一旦传下来的数据诸如字节未对齐,多次IO等会极大影响IO的性能。

5.      减少不必要的文件开关操作;大部分的文件系统中,文件的属性数据和文件的真实数据是分开存放的,open一个文件时,操作系统要先找到文件的属性数据将这些数据载入到内存,然后根据属性数据再偏移到文件真实数据存放的扇区对数据进行操作;close时一般操作系统会强制刷新数据到存储设备,然后再偏移到文件的属性数据存放的扇区更新属性信息,同样也会强制刷新数据;

6.      减少调用IO的频率,能一次写完的数据不要分成多次;这一点其实跟IO关系不大,主要是linux的关系;linux系统分为用户态和系统态(或叫内核态);一般的操作都是在用户态下进行的,而一些系统调用需要先切换到系统态才能执行,切换时需要将当前环境压入到寄存器,操作完成后再从寄存器中读取环境信息来进行恢复;减少IO的调用次数可以减少系统状态切换的开销。

IO流程及优化的更多相关文章

  1. elasticsearch的数据写入流程及优化

    Elasticsearch 写入流程及优化 一. 集群分片设置:ES一旦创建好索引后,就无法调整分片的设置,而在ES中,一个分片实际上对应一个lucene 索引,而lucene索引的读写会占用很多的系 ...

  2. Linux 0.11源码阅读笔记-文件IO流程

    文件IO流程 用户进程read.write在高速缓冲块上读写数据,高速缓冲块和块设备交换数据. 什么时机将磁盘块数据读到缓冲块? 什么时机将缓冲块数据刷到磁盘块? 函数调用关系 read/write( ...

  3. 【转】IO流程

    原文地址:http://blog.chinaunix.net/uid-26922071-id-3954900.html IO之流程与buffer概览 为了说明这个流程,还是用图来描述一下比较直观.   ...

  4. MySQL优化篇(一),我可以和面试官多聊几句吗?——SQL优化流程与优化数据库对象

    我可以和面试官多聊几句吗?只是想偷点技能过来.MySQL优化篇(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. MyISAM表锁和InnoD ...

  5. slave IO流程之一:mysql登陆过程(mysql_real_connect)

    最近看了slave IO的源码,发现slave IO的写relay log貌似是单线程单连接的,这让我有点小失望. slave IO的主函数是handle_slave_io,处理流程如下: 图1 ha ...

  6. [搜片神器]DHT后台管理程序数据库流程设计优化学习交流

    谢谢园子朋友的支持,已经找到个VPS进行测试,国外的服务器: sosobt.com 大家可以给提点意见... 服务器在抓取和处理同时进行,所以访问速度慢是有些的,特别是搜索速度通过SQL的like来查 ...

  7. kvm和qemu交互处理io流程

    1.IO虚拟化的分类 (1)全虚拟化:宿主机截获客户机对I/O设备的访问请求,然后通过软件模拟真实的硬件.这种方式对客户机而言非常透明,无需考虑底层硬件的情况,不需要修改操作系统. QEMU模拟I/O ...

  8. 数据库的IO and 数据库优化问题

    一.IO介绍 IO有四种类型:连续读,随机读,随机写和连续写,连续读写的IO size通常比较大(128KB-1MB),主要衡量吞吐量,而随机读写的IO size比较小(小于8KB),主要衡量IOPS ...

  9. 磁盘IO概念及优化入门知识

    在数据库优化和存储规划过程中,总会提到IO的一些重要概念,在这里就详细记录一下,对这个概念的熟悉程度也决定了对数据库与存储优化的理解程度,以下这些概念并非权威文档,权威程度肯定就不能说了. 读/写IO ...

随机推荐

  1. Mitmproxy介绍及Python拦截代理

    使用 mitmproxy + python 做拦截代理 转自:https://blog.wolfogre.com/posts/usage-of-mitmproxy/   本文是一个较为完整的 mitm ...

  2. OC基础:类的扩展.协议 分类: ios学习 OC 2015-06-22 19:22 34人阅读 评论(0) 收藏

    //再设计一个类的时候,有些方法需要对外公开(接口),有些仅供内部使用. 类的扩展:为类添加新的特征(属性)或者方法 对已知类: 1.直接添加 2.继承(在其子类中添加实例变量和方法) 3.使用ext ...

  3. Java中多线程

    引 如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个 ...

  4. HDU 2907

    http://acm.hdu.edu.cn/showproblem.php?pid=2907 ans=(凸包顶点数-凸包凹面数量)*q-凸包凹面数量*p 重点在求一个凸包的凹面数量,极角排序过后,当前 ...

  5. 【论文解读】行人检测:What Can Help Pedestrian Detection?(CVPR'17)

    前言 本篇文章出自CVPR2017,四名作者为Tsinghua University,Peking University, 外加两名来自Megvii(旷视科技)的大佬. 文章中对能够帮助行人检测的ex ...

  6. Unity 3D游戏-NPC对话系统With XML

    用XML做的Unity NPC对话系统 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 Create X ...

  7. Python实现不同格式打印九九乘法表

    前言:最近在学习Python,学习资源有慕课网上的视频教程.菜鸟教程以及Python官方文档tutorial.虽然了解了Python的基本语法,但是还没有真正意义上输出自己写的代码.代码小白,之前仅学 ...

  8. 实习第一天:try和catch的使用

    package wo;public class wowo{ public static void main(String[] args){ try{ // int i = 1/0; 是没有语法错误的, ...

  9. day36 python学习gevent io 多路复用 socketserver *****

    ---恢复内容开始--- gevent 1.切换+保存状态 2.检测单线程下任务的IO,实现遇到IO自动切换 Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在geven ...

  10. 开源泛域名服务xip.io部署试用

    xip.io 是一个很方便的泛域名服务,类似的有一个xip.name 的开源实现 下载 go get github.com/peterhellberg/xip.name 启动 二进制包在GOPATH/ ...