块I/O层(I/O调度)

来源:互联网 发布:好用的面霜 知乎 编辑:程序博客网 时间:2024/05/16 23:33

块I/O层(I/O调度)

 

    Linux中的设备分为块设备和字符设备。块设备是能够随机访问(不需要按顺序)固定大小数据片的硬件设备,如硬盘、软盘等。字符设备是只能按照字符流的方式被有序的访问,不能随机的跳转的设备,如键盘和串口设备。这两种设备的区别可以通俗的概括为:能否在访问设备时随意的从一个位置跳转到另一个位置。举个例子,硬盘设备的驱动可能要求读取键盘上的任意块的内容,然后又转去读取别的块的内容,而被读取的块在磁盘上的位置不一定要连续;而对于键盘这种设备提供的就是一个数据流,当你输入”wolf”字符串时,只能按顺序读取每一个字符流,先读’w’后读’o’、’l’、’f’,不能打乱读取的顺序。内核管理块设备要比管理字符设备细致的多,需要考虑的问题和完成的工作相对于字符设备来说要复杂的多,这是因为字符设备仅仅需要控制一个位置—当前位置,而块设备访问的位置必须能够在介质的不同区间前后移动,所以内核不必提供专门的字符设备子系统,但却有一个块I/O子系统来管理块I/O层。

    I/O调度程序的主要工作就是管理I/O请求队列。块设备将它们挂起的I/O保存在请求队列中,只要请求队列不为空,队列对应的块设备驱动程序就会从队列头获取请求,然后将其送入对应的块设备上去。但是如果只是简单的以内核产生的请求次序直接将请求发送到块设备的话,性能肯定非常差。为了优化寻址操作,I/O调度程序先对请求队列中挂起的请求进行合并和排序,然后再将I/O资源分配给挂起的I/O请求。合并是将相邻的磁盘扇区请求操作合并成一个请求,从而减少I/O的次数。排序是将整个请求队列按照扇区增长方向有序排列,然后将排序后的请求队列按照I/O调度算法进行资源的分配,具体有一下几种调度算法:

    Linus电梯

该算法在2.4内核中是默认的I/O调度程序,在2.6内核中被其他两个调度程序取代了。算法首先进行合并和排序的预处理。当有新的请求加入队列时,它首先会检查挂起的请求是否可以和新请求合并,如果可以先进行合并,然后寻找可能的插入点。如果找到,新的请求被插入到该点(新请求在队列中的位置必须符合请求以扇区方向有序排列的原则),如果没有合适的位置,那么新的请求就被加入到队列的末尾。另外,如果发现队列中有驻留时间过长的请求,那么新请求也将被加入到队列的末尾,这样做是为了避免由于访问相近磁盘位置的请求太多,从而使磁盘其他位置的请求难以得到执行。

进行合并排序后,调度算法是按照磁头移动方向的顺序进行调度,显示从低扇区到高扇区,到达磁盘末尾时,磁头再换另一个方向移动到另一端,就像是电梯一样。

    最终期限I/O调度程序

最终期限I/O调度程序是为了解决Linus电梯所带来的饥饿问题而提出来的。出于减少磁盘寻址时间的考虑,对某个磁盘扇区域上的繁重操作,无疑会使得磁盘其他位置上的操作请求得不到运行的机会,更糟糕的是,普通的请求饥饿还会带来写-饥饿-读这种特殊的问题。由于写操作是异步的(即发出一个写磁盘命令后,可以不需要等待写操作结束就可以继续后面的操作),但是读操作是同步的(即在没有完成读操作之前,即没有获得数据之前,不能进行后面的操作),所以读操作的响应时间对于系统的性能非常重要。注意,减少请求饥饿必须以降低全局吞吐量为代价。

在最终期限I/O调度程序中,每个请求都有一个超时时间。默认情况下,读请求的超时时间为500ms,写请求的为5s。最终期限I/O调度程序维持三个请求队列:一个是和Linus电梯一样的排序队列,另外两个是按照FIFO排列的读请求FIFO队列和写请求FIFO队列,每个新请求都加入到这两个队列的末尾,这样就使队头的请求最先超时,但是每个请求还是按照Linus电梯算法那样加入到排序队列。对于普通的操作来说,最终期限I/O调度程序将请求从排序队列的头部取下,推入到派发队列中,派发队列然后将请求提交给磁盘驱动,但是如果在两个FIFO请求队列头的请求超时时,那么最终期限I/O调度程序便从FIFO队列中提取出请求进行服务。注意,最终期限I/O调度程序并不能严格保证请求的响应时间,但是通常情况下,可以在请求超时或超时前提交和执行,以防止请求饥饿现象的发生。

 

    预测I/O调度程序

虽然最终期限I/O调度程序为降低读操作响应时间做了许多工作,但是它同时也降低了系统吞吐量。假设当前正出于进行繁重写操作期间,当读操作超时时,进行读操作,结束后又返回进行写操作,这样不断的寻址切换会降低系统全局吞吐量。预测I/O调度程序的目标就是在保持良好的读响应时间的同时也能提供良好的全局吞吐量。预测I/O调度程序的基础仍然是最后期限I/O调度程序,也维持了三个队列,它的主要改进是增加了预测启发能力。预测I/O调度程序每次提交读请求后并不直接返回处理其他请求,而是会有几ms的等待时间,这段时间对于应用程序来说是个提交其他读请求的好机会—任何相邻磁盘位置操作的请求都会立刻得到处理。在等待时间结束后,预测I/O调度程序重新返回原来的位置,继续执行以前剩下的请求。当然,如果没有I/O请求在等待期到来,那么预测I/O调度程序会给系统带来轻微的损失,但是,如果预测准确率较高,即存在愈来愈多的访问同样区域的读请求到来,那么片刻等待无疑会避免大量的寻址操作。

原创粉丝点击