Linux内核设计与实现 十四、块I/O层

块设备

 系统中能够随机(不需要按数据)访问固定大小数据片的硬件设备称作块设备,这些固定大小的数据片就称作块。最常见的块设备是硬盘。

字符设备

 字符设备按照字符流的方式被有序访问,像串口和键盘就属于字符设备。

区别

 区别在于是否可以随机访问数据。
 内核管理块设备比管理字符设备细致得多。因为字符设备仅仅需要控制当前位置。而块设备访问的位置必须能够在介质的不同区间前后移动。
 块设备的管理需要有一个专门的提供服务的子系统,字符设备不需要。不仅因为块设备的复杂性高,块设备对执行性能的要求很高。对硬盘每多一份利用都会对整个系统的性能带来提升。

14.1 剖析一个块设备

扇区

 块设备中的最小的可寻址单元是扇区,扇区的大小是设备的物理属性。扇区是所有块设备的基本单元——块设备无法对比扇区还小的单元进行寻址和操作。

 软件的最小逻辑可寻址单元是块。块是文件系统的一种抽象,只能基于块来访问文件系统。

 物理磁盘寻址按照扇区级进行,但是内核执行的所有磁盘操作都是按照块进行的。

二者关系

 扇区是设备的最小可寻址单元,所以块不能比扇区还小,只能数倍于扇区大小。
在这里插入图片描述

二者别名

●扇区:有时称作“硬扇区”或“设备块”
●块:有时称作“文件块”或“I/O”块

14.2 缓冲区和缓冲区头

缓冲区

作用
 当一个快被调入内存时,要存储在一个缓冲区中。每个缓冲区与一个块对应,相当于是磁盘块在内存中的表示。

缓冲区头

概念
 每一个缓冲区都有一个对应的描述符。该描述符用buffer_head结构体表示,称作缓冲区头,包含了内核操作缓冲区所需要的全部信息。
在这里插入图片描述
目的
 在于描述磁盘块和物理内存缓冲区之间的映射关系。

2.6内核以前
 以前缓冲区头的作用比现在更重要。因为缓冲区头还是所有块I/O操作的容器,这样做有两个弊端
●缓冲区头很大且不易控制,对数据的操作不方便也不清晰。内核更倾向于操作页面结构,因为页面操作起来更为简便,效率也高。
●仅能描述单个缓冲区,当作为所有I/O的容器使用时,缓冲区头会促使内核把大块数据的I/O操作分解为对多个buffer_head结构体进行操作。会造成不必要的负担和空间浪费。

2.6及以后
 引入了一种新型、灵活并且轻量级的容器,即bio结构体。

14.3 bio结构体

概念
 目前内核中块I/O的基本容器由bio结构体表示。该结构体代表了活动的以片断链表形式组织的块I/O操作。一个片断是一小块连续的内存缓冲区。
作用
 不需要保证单个缓冲区一定要连续。即使一个缓冲区分散在内存的多个位置上,bio结构体也能对内核保证I/O操作的执行。
在这里插入图片描述

在这里插入图片描述

I/O向量

 bi_io_vec域指向一个bio_vec结构体数组,该结构体链表包含了一个I/O操作所需要用到的所有片段。每个bio_vec结构都是一个形式为<page, offset, len>的向量,它描述的是一个特定的片段:片段所在的物理页、块在物理页中的偏移位置、从给定偏移量开始的块长度。
在这里插入图片描述
 在每个给定的块I/O操作中,bi_vcnt域用来描述bi_io_vec所指向的vio_vec数组中的向量数目。当块I/O操作执行完毕后,bi_idx域指向数组的当前索引。
工作原理
 每一个块I/O请求都通过一个bio结构体表示。每个请求包含一个或多个块,这些块存储在bio-vec结构体数组中。这些结构体描述了每个片段在物理页中的实际位置。I/O操作的第一个片段由b_io_vec结构体指向,其他的片段在其后放置。当块I/O层开始执行请求、需要使用各个片段时,bi_idx域会不断更新,从而指向当前片段。

新老方法对比(bio和缓冲区头)

在这里插入图片描述

14.4 请求队列

请求队列
 块设备将它们挂起的块I/O请求保存在请求队列中,该队列由reques_queue结构体表示,请求队列只要不为空,队列对应的块设备驱动程序就会从队列头获取请求,然后将其送入对应的块设备上去。请求队列表中每一项都是一个单独的请求,由request结构体表示。
request结构体
 队列中的请求由结构体request表示。因为一个请求可能要操作多个连续的磁盘块,所以每个请求可以由多个bio结构体组成。每个bio结构体都可以描述多个片段。

14.5 I/O调度程序

磁盘寻址
 磁盘寻址是整个计算机中最慢的操作之一,每一次寻址需要花费不少时间,尽量缩短寻址时间是提高系统性能的关键。

优化寻址操作
 内核不会简单地按请求接收次序,也不会立即将其提交给磁盘。而是在提交前执行名为合并与排序的与操作。这种预操作可以极大地提高系统的整体性能。在内核中负责提交I/O请求的子系统称为I/O调度程序。

I/O调度程序
 将磁盘I/O资源分配给系统中所有挂起的块I/O请求。这种资源分配是通过将请求队列中挂起的请求合并和排序来完成的。

I/O调度和进程调度
●共同点:将一个资源虚拟给多个对象。
●不同点:进程调度程序将处理器资源分配给系统中的运行进程。I/O调度程序虚拟块设备给多个磁盘请求,以便降低磁盘寻址时间。

I/O调度程序的工作

工作
 管理块设备的请求队列。有利于减少磁盘寻址时间,从而提高全局(可能牺牲某些请求性能)吞吐量。

方法
 I/O调度程序通过两种方法减少磁盘寻址时间:合并与排序。
●合并:
 将两个或多个请求结合成一个新请求。可以减小请求次数,并且减少寻址次数。
 例如两个请求访问的磁盘扇区相邻,就可以合并为一个新请求。
●排序:
 整个请求队列将按扇区增长方向有序排列。使所有请求按硬盘上扇区的排列顺序有序排列,不仅可以缩短单独一次请求的寻址时间。更重要的在于,通过保持磁盘头以直线方向移动,缩短了所有请求的磁盘寻址时间。
 该算法类似于电梯调度:电梯不能随意地从一层跳到另一侧,它应该一个方向移动,当抵达了同一方向上的最后一层厚,再掉头向另一个方向移动。

Linus电梯

应用
 Linux中实际使用的I/O调度程序。在2.6版本被取代。这个程序更为简单,并且执行的许多功能都相似。

工作
在这里插入图片描述

最终期限I/O调度程序(deadline)

目的
 解决Linus电梯所带来的的饥饿问题。一个磁盘对同一位置操作的请求流可以造成较远位置的其他请求永远得不到运行机会,这是一种很不公平的饥饿现象。
 解决写—饥饿—读这种特殊问题。在读请求发生时,应用程序通常会阻塞直到读请求被满足。所以读响应时间对系统的性能很重要。而写响应时间没有那么重要。

思想
 最后期限I/O调度程序中,每个请求都有一个超时时间,读为500ms,写为5s,可以防止饥饿现象的发生。

预测I/O调度程序

目的
 最后期限I/O调度程序为降低读操作响应时间做了许多工作,但是它同时降低了系统吞吐量。
 假设系统处于繁重的写操作期间,每次提交读请求,都会迅速处理读请求,所以磁盘首先为读操作进行寻址,执行读操作,再返回寻址进行写操作。两次寻址损害了全局吞吐量。
 预测I/O调度程序的目标就是在保持良好的读响应的同时也能提供良好的全局吞吐量。

应用
 Linux内核中缺省的I/O调度程序,对大多数工作负荷来说执行良好,对服务器也是理想的。不过在某些非常见的服务器上(如数据库挖掘服务器),这个调度程序执行的效果不好。

思想
 增加了预测启发能力
 读请求提交后并不直接返回处理其他请求,而是有意空闲几ms。这几ms让其他应用程序提交读请求,任何相邻磁盘位置操作的请求都会立刻得到处理。等待时间结束后,程序重新返回到原来的位置,继续执行以前剩下的请求。
 如果没有I/O请求在等待期到来,那么就会浪费掉几ms,损失不大

完全工作的排队I/O调度程序(CFQ)

思想
 每个进程有自己的I/O请求队列,CFQ以时间片轮转调度对了,从每个队列中选取请求数,然后进行下一轮调度。在进程级提供了公平。

应用
 主要推荐给桌面工作负荷使用,但是如果没有其他异常,在几乎所有的工作负荷中都能很好地执行。

空操作的I/O调度程序

思想
 基本上是一个空操作,会执行合并。除此之外不做什么。因为真正的随机访问设备没有“寻道”的负担。

应用
 应用于真正的随机访问设备。

I/O调度程序的选择

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值