文档章节

I/O管理

China_OS
 China_OS
发布于 2012/12/08 08:55
字数 3713
阅读 198
收藏 0

     系统中能够随机访问固定大小数据片的硬件设备成为块设备,这些固定大小的数据片就称为块,最常见的就是硬盘,他们都是以安装文件系统的方式使用的,这也是块设备一般的访问方式。另一种基本的设备类型是字符设备,字符设备按照字符流的方式被有序访问,如键盘。这两种设备的区别就在于是否可以随机访问数据。内核管理块设备要比管理字符设备细致很多,因为字符设备仅仅需要控制一个位置--当前位置,而块设备访问的位置必须能够在介质的不同区间前后移动。

剖析一个块设备
     块设备中最小的寻址单元是扇区,扇区大小一般是2的整数倍,常见的为512字节,扇区的大小是物理设备的属性,扇区是所有块设备的基本单元,块设备无法对比扇区还小的单元进行操作。

     而各种软件都会用到自己的最小逻辑可寻址单元-块。块是文件系统的一种抽象,只能基于块来访问文件系统,虽然物理磁盘是按照扇区进行操作的,但是内核执行所有的磁盘操作都是按照块来进行的,由于扇区是最小的可寻址单元,所以块不能比扇区小,只能是扇区的整数倍,并且不能超过一个页的长度。扇区之所以对内核重要是因为所有设备的IO必须是以扇区为单位进行操作,而内核使用的块这一概念是建立在扇区之上的。

缓冲区和缓冲区头
     当一个块被调入内存时,他要被存入缓冲区中,每个缓冲区与一个块对应,它相当于磁盘块在内存中的表示,所以一个页中可以有多个块,内核在管理数据时需要一些信息,所以每个缓冲区都有一个对应的描述符叫缓冲区头,该描述符用buffer_head结构体表示。

struct buffer_head {
        unsigned long        b_state;          /* buffer state flags */
        atomic_t             b_count;          /* buffer usage counter */
        struct buffer_head   *b_this_page;     /* buffers using this page */
        struct page          *b_page;          /* page storing this buffer */
        sector_t             b_blocknr;        /* logical block number */
        u32                  b_size;           /* block size (in bytes) */
        char                 *b_data;          /* buffer in the page */
        struct block_device  *b_bdev;          /* device where block resides */
        bh_end_io_t          *b_end_io;        /* I/O completion method */
        void                 *b_private;       /* data for completion method */
        struct list_head     b_assoc_buffers;  /* list of associated mappings */
};

     在操作缓冲区头之前,应该先使用get_bh()函数增加缓冲区头的引用计数,确保该缓冲区头不会再被分配出去,当完成对缓冲区头的操作后,必须调用put_bh()减少引用计数。缓冲区头的目的在于描述磁盘块和物理内存缓冲区之间的映射关系,说明从缓冲区到块的映射关系。可是将缓冲区作为IO操作单元带来了两个弊端,首先缓冲区头是一个很大且不容易控制的数据结构体,而且缓冲区头对数据的操作既不方便也不高效,内核更倾向于操作页面,所以在2.6内核中,许多IO操作都是直接通过内核操作页面,不再使用缓冲区头。其次,他仅能描述单个缓冲区,当做为所有IO的容器使用时,缓冲区头会促使内核把对大块数据的操作分解为对多个buffer_head结构体进行操作,这样会造成不必要的负担和浪费,因此引进了bio结构体。

BIO结构体
     目前内核中块IO操作的基本容器是由bio结构体表示的,该结构体代表了正在活动的以片段链表形式组织的块IO操作,一个片段是一小块连续的内存缓冲区,这样不需要单个缓冲区是连续的,即使一个缓冲区分散在内存的多个位置上,bio结构体也能保证内核的IO操作执行。bio的主要目的是代表正在活动的IO操作,所以该结构体中的域主要是用来管理相关信息的。

struct bio {
        sector_t             bi_sector;         /* associated sector on disk */
        struct bio           *bi_next;          /* list of requests */
        struct block_device  *bi_bdev;          /* associated block device */
        unsigned long        bi_flags;          /* status and command flags */
        unsigned long        bi_rw;             /* read or write? */
        unsigned short       bi_vcnt;           /* number of bio_vecs off */
        unsigned short       bi_idx;            /* current index in bi_io_vec */
        unsigned short       bi_phys_segments;  /* number of segments after coalescing */
        unsigned short       bi_hw_segments;    /* number of segments after remapping */
        unsigned int         bi_size;           /* I/O count */
        unsigned int         bi_hw_front_size;  /* size of the first mergeable segment */
        unsigned int         bi_hw_back_size;   /* size of the last mergeable segment */
        unsigned int         bi_max_vecs;       /* maximum bio_vecs possible */
        struct bio_vec       *bi_io_vec;        /* bio_vec list */
        bio_end_io_t         *bi_end_io;        /* I/O completion method */
        atomic_t             bi_cnt;            /* usage counter */
        void                 *bi_private;       /* owner-private method */
        bio_destructor_t     *bi_destructor;    /* destructor method */
};

      

 

     bi_io_vec域指向一个bio_vec结构体数组,该结构体包含一个IO操作所需要使用的所有片段,每个bio_vec结构都是形式为<page,offset,len>的向量,他描述的是一个特定的片段:片段所在的物理页,在物理页中的偏移位置,从偏移位置起的长度。bio_io_vec结构体表示了一个完整的缓冲区,在每个指定块IO的操作中,bi_vcnt域用来描述bi_io_vec所指向的vio_vec数组中的向量数目,当块IO操作执行完毕后,bi_idx域指向数组的当前索引,总之,每一个块IO请求都通过一个bio结构体表示,每个请求包含一个或者多个块,这些块存储在bio_vec结构体数组中,这些结构体描述了每个物理片段在物理页中的实际位置,像向量一样被组织起来。

新老对比
     缓冲区头和bio结构体存在显著的差别,bio结构体代表的是IO操作,他可以包括内存中的一个或者多个页,而buffer_head结构体代表一个缓冲区,他描述的是磁盘中的一个块。因为缓冲区头中关联的是单独页中的单独磁盘块,所以他可能会引起不必要的分隔,将请求按块为单位进行分隔,而bio描述的块不需要连续的存储区域,所以不需要分隔IO操作。虽然bio结构体比缓冲区头有很多优势,但是我们还是需要缓冲区头这个概念,因为缓冲区头还负责描述磁盘块到页面的映射,bio结构体不包含任何和缓冲区相关的状态信息,他仅仅描述一个或者多个单独块IO操作的数据片段和相关信息。内核使用这两种结构保存各自的信息,可以保证每种结构所包含的信息量尽可能少。

请求队列
      块设备将他们挂起的块IO请求保存在请求队列中,该队列有request_queue结构体表示,他包含一个双向链表及相关的控制信息。请求队列只要不为空,队列对应的块设备驱动程序就会从队列头获取请求,然后将其送入对应的块设备上去,请求队列表中的每一项都是一个单独的请求,由request结构体表示。因为一个请求可能要操作多个连续的磁盘块,所以每个请求可以由多个bio结构体组成。

IO调度程序
     为了优化寻址操作,内核既不会简单的按照请求的接收次序,也不会立即将其提交给磁盘,相反,他在提交前先执行名为合并与排序的预操作。在内核总负责提交IO请求的子系统称为IO调度程序。IO调度程序将磁盘IO资源分配给系统中所有挂起的IO请求,这种资源分配是通过将请求队列中挂起的请求合并和排序来完成的。

     IO调度程序主要是管理块设备的请求队列,IO调度程序通过两种方法减少磁盘寻址时间:合并与排序。合并是指将多个请求合并成一个新的请求,如果队列中并不需要操作相邻扇区的其他请求,此时就无法将当前请求与其他请求合并。整个请求队列按照扇区增长方向有序排列,使所有请求按硬盘上扇区的排列顺序有序排列的目的不仅是为了缩短单独一次请求的寻址时间,更重要的优化在于通过保持磁盘头以直线方向移动,缩短了所有请求的磁盘寻址时间。


linus电梯
     在2.4内核中linus电梯调度算法是默认的IO调度程序,在2.6内核中被其他算法所取代了。linus电梯执行合并与排序,有新请求加入队列时,他会先检查其他每一个挂起来的请求是否可以和新请求合并,合并可以向前合并,也可以向后合并,向后合并的居多。如果合并失败,那么就寻找可能的插入点,新请求在队列中的位置必须符合请求以扇区方向有序排列的原则,如果找到合适的点,则插入,如果没有合适的点,那么新请求被插入队列尾部,如果队列中有驻留时间过长的请求,新请求也会被加入队列尾部。总的来说执行如下:
      1 如果队列中存在一个对相邻磁盘扇区的操作请求,那么请求将和这个已经存在的请求合并成一个请求。
      2 如果队列中存在一个驻留时间过长的请求,那么新的请求会插入队列尾部,防止其他请求饥饿发生。
      3 如果队列中以扇区方向为序存在合适的插入位置,那么新的请求将被插入到该位置。
      4 如果队列中不存在合适的请求插入位置,则请求被插入到队列尾部。

deadline IO调度程序
     最终期限调度程序是为了解决linus电梯所带来的饥饿问题而提出的,更糟糕的是普通的饥饿请求还会带来名为写-饥饿-读的这种特殊的问题。写操作通常是在内核有空时将请求提交给磁盘的,写操作完全和提交他的应用程序是异步执行,而读操作则相反,通常一个程序提交读请求时,应用程序会发生堵塞直到读请求被满足。为了减少请求饥饿必须以降低全局吞吐量为代价。在最后期限的IO调度程序中,每个请求都有一个超时时间,默认情况下,读请求的超时时间是500ms,写请求的超时时间是5s。最后期限IO调度类似于linus电梯,但是最后期限IO调度也会以请求类型为依据将他们插入到额外的队列中,读请求按次序被插入到特定的读FIFO队列中,写请求被插入到特定的写FIFO队列中。对于普通的操作来说,最后期限IO调度程序将请求从排序队列的头部取下,再放入分发队列中,分发队列然后将请求提交给磁盘驱动。如果在写FIFO队列或者读FIFO队列的头部请求超时,那么最后期限IO调度程序便会从FIFO队列中提取请求进行服务,防止饥饿发生,最后期限IO调度并不能严格保证请求的响应时间,一般情况下会在超时前提交和执行。


预测IO调度程序
     虽然最后期限IO调度程序为防止饥饿做了很多工作,但是同时也降低了系统的吞吐量,预测IO调度程序的目标是为了在保持良好的读响应的同时提供良好的吞吐量,预测IO调度的基础仍然是最后期限IO调度程序,他最主要的改进是增加了预测启发能力。预测IO调度试图减少在进行IO操作期间,处理新到的读请求所带来的寻址数量,预测IO调度程序的不同之处在于,请求提交后并不直接返回处理其他请求,而是有意空闲片刻,空闲的这段时间,对其他应用程序来说是提交其他读请求的好机会,任何对相邻磁盘位置操作的请求都会立刻得到处理。在等待时间结束后,预测IO调度程序重新返回原来的位置,继续执行以前剩下的请求。但是,如果没有IO请求在等待期到来,那么预测IO调度程序会给系统性能带来轻微的损失,预测IO调度程序带来的优势取决于能否正确预测应用程序和文件系统的行为。

完全公正的排队IO调度程序
     完全公正的排队IO调度程序是为专有工作负荷设计的,但是,他与前面的调度程序有根本的不同。CFQ IO调度程序把进入的IO请求放入特定的队列中,这种队列是根据引起IO请求的进程组织的,在每个队列中,刚进入的请求与相邻的请求合并在一起,并进行插入分类。CFQ IO调度程序的差异在于每一个提交IO请求的进程都有自己的队列,CFQ IO调度程序以时间片轮转调度队列,从每个队列中选取请求数(默认4),然后进行下一轮调度。这就在进程及提供了公平,确保每个进程接收公平的磁盘带宽片段。

空操作的IO调度程序
     空操作IO调度程序基本上是一个空操作,不做多少事情,空操作IO程序不进行排序,也没有其他形式的寻址操作,不过,空操作程序会执行合并程序,除了这一操作外,他不再做什么,只维护请求队列以近乎FIFO的顺序排列。空操作IO调度程序不勤奋是由道理的,因为他打算用在块设备,那是真正随机访问的设备,那么就没有必要进行插入排序。



© 著作权归作者所有

共有 人打赏支持
China_OS
粉丝 406
博文 440
码字总数 493809
作品 0
徐汇
技术主管
数据中心虚拟化和云端解决方案--OpenNebula

OpenNEbula 是开放原始码的 虚拟基础设备引擎 用来动态布署虚拟机器在一群实体资源上,ONE (OpenNEbula) 最大的特色在于将虚拟平台从单一实体机器到一群实体资源 ONE 是 Reservoir Project ...

匿名
2010/04/22
14.5K
2
微服务架构企业级增强产品,数人云推出统一配置中心Hawk

微服务架构企业级增强产品,数人云推出统一配置中心Hawk 数人云博客2017-11-221 阅读 架构服务产品配置 11月16日,数人云在PaaS Innovation大会上,正式发布企业应用架构管理体系EAMS,这是数...

数人云博客
2017/11/22
0
0
私有云实施中,OpenStack虚拟机管理程序很重要

导读 OpenStack的虚拟机管理程序非常重要。为支持和确保私有云集成,应该考虑成熟度、安全功能和管理选项等因素。 私有云为企业带来了许多与公有云类似的好处,例如自动化、自助服务、灵活性...

lq1ns259ej3okyvk4jf
2017/12/04
0
0
修改计算机名,sharepoint站点打不开的解决办法

转载自:http://blog.163.com/li_wangyuan/blog/static/520600620105219733368/ 在MSOTEC上面看到的文章,以前碰到過,發出來給大家分享: 若修改了计算机的名字,密码等,sharepoint所有站点都...

yuxye
2016/12/29
0
0
现实世界的Windows Azure:采访InishTech的销售及市场部主管Andrew O’Connor

MSDN: 告诉我们关于你们公司的信息以及您为Windows Azure创建的解决方案。 O’Connor: InishTech 有点不寻常。我们的软件许可和保护服务(SLPS)平台是一个传统的多租户Windows Azure应用程序...

晨曦之光
2012/03/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

使用esp8266制作wifi干扰器

概述 这个东西,说真的对现在的无线网络环境影响其实不是很大了,首先它只能玩2.4ghz的无线,其次这个模块不是特别的可靠,运行的时候温度会很高,买来玩玩还是可以的 什么是esp8266 ESP8266...

bboysoulcn
13分钟前
0
0
以太坊总结

一、概念说明 1.以太坊(Ethereum blockchain)由V神(Vitalik Buterin)发明,是一个交易记录的永久数据库,它以一个“无信任”的交易系统来运行,不需要任何第三方信任机构即可进行点对点的...

盼望明天
38分钟前
1
0
Java并发工具类——AtomicInteger

基本类型int的递增等操作并不是线程安全的,加上synchronized又会影响性能,因此在并发情况下我们应该使用AtomicInteger,下面通过一个例子验证一哈。 public class TestAtomicInteger {...

东都大狼狗
40分钟前
2
0
基于CentOS7.2系统对RabbitMQ单机版安装过程

准备虚拟机系统 我的系统如下 系统版本7.2 安装perl yum install perl 安装wget工具 yum install -y wget 安装相关依赖工具 yum install ncurses ncurses-base ncurses-devel ncurses-libs ...

凌晨一点
44分钟前
1
0
Maven常用命令

Maven常用命令 说到命令,则不得不提一下环境变量,在之前的博文中简单提了一下环境变量的配置,这里具体说一下。说完环境变量的配置,然后就是Maven的常用命令,这里说的是常用的几个命令,...

星汉
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部