IO调度策略之我见

简介:

IO调度策略对上面的块设备层和下面的磁盘驱动起作用,它实质上切断了数据从应用程序到磁盘的路径,从而也就解除了块设备和底层驱动程序之间的耦合,这样的话就可以匹配上下两层之间的不和谐,试想如果磁盘速度很慢,那么就可以在IO调度策略中加入可以避免过多寻道的操作,比如AS预测调度器,比如合并不同的请求,但是对于Flash-DOM之类的可以随机存储的存储器就没有必要采用复杂的调度算法了。对于linux的实现,IO调度模块对上层实际上就是一个入队操作,根据系统管理员的配置或者自适应决断结果将一系列IO请求分配到一系列队列中,入队的策略主要在于怎么排队,比如一共有哪些队列,一个请求应该排入哪个队列,之后的事情就不用管了,而出队操作是IO调度模块下层的接口,它主要负责从哪个队列选择下一个要服务的请求,它不管块设备层是怎么将请求排入队列的,然而到此为止了吗?为了使得一些策略起作用,同时也为了使得“跨层操作”最小化,所谓的队列中必须积攒了一定数量的IO请求的时候才能激发调度,也就是说块设备层不断的将请求加入到策略化的队列中,而驱动程序并不是马上就对队列中的请求进行服务,而是等到队列中的请求积攒到一定数量的时候再开始服务过程。我们知道,计算机中,凡是跨层操作,开销几乎一定大于层内操作,这是因为分层是为了解耦合,是为了机制和策略分离,层与层之间抽象出了接口,而接口需要确保极大的兼容性,所以为了照顾接口的兼容性和其本身的安全性稳定性以及正交性,也就必然需要将问题一般化,因此就需要一个环境的切换,因此性能的牺牲也是必然的,我们常常听说尽量少进行系统调用也就是这个道理,对应到IO调度层也是这个道理,因此我们千万不要要求磁盘驱动程序不断的取得请求不断的服务,让它休息一会也许会取得更好的性能。linux的实现中,用了一个十分形象的方式实现了这个,plug和unplug,这两个词汇从其本意上就能让人理解linux的实现方式,plug是活塞,unplug是拔下活塞的意思,起初,在队列的开头赛上一个活塞(plug),待到队列中的请求达到一定数量后者塞上活塞已经有一段时间以后,那么拔下活塞(unplug,每个磁盘的请求队列都有一个unplug回调函数),这么解释就什么都清楚了。

IO调度有很多策略,起初就是linus电梯,这个算法很直观同时也必然很简单,2.6内核之后,添进来很多算法,我总结了一下基本就是两点,其中cfq是按照网络负载均衡算法改造的,而其他的算法都是对linus电梯的改进,deadline算法避免了饥饿,避免了磁盘中临近的区域大量的请求被瞬间提交,从而造成早期提交的一个稍微远一些的请求饥饿,因为deadline算法中每一个请求都有一个饥饿时间限制值,一个请求同时要插入到两个队列,其中一个队列是linus电梯里面的队列,另一个是FIFO的按照到达时间排序的队列,这个FIFO队列也按照read和write进行了区分,read队列的饥饿时间限制要更短一些,因为应用程序对于读请求一般都是同步意义的,并且对于磁盘文件来讲如果顺序读的话,前面的读没有完成后面的读更是无法进行,而写操作就不是这样的,应用程序写文件一般都是异步意义上的,更复杂的,如果很多进程都在写一个文件的一个区域,那么只要最后一个写操作完成就可以了,前面的几个都可以直接抛弃,再者,写入缓存还是写入磁盘,这都不是应用程序所关心的,因此写操作的超时时间要大于读操作,deadline在linus电梯的基础上避免了饥饿,那么引入了另一个问题,试想如果一系列写操作正在进行,这些写操作都是经过linus电梯算法合并和排序过的,这时突然有个读请求饥饿超时到时间了,那么不可避免的,磁头要移动到读请求的位置,这样显然降低了磁盘的吞吐量,然而这个突然的移动还不得不做,读请求完成以后,按照deadline的逻辑,磁盘的磁头又返回刚才被读请求打断的写请求的位置,然后...,这一次又一次的移动,不断降低着磁盘的吞吐量,并且磁头频繁移动,损坏磁盘,AS算法出现了,在不得不服务超时读请求后,不是返回写请求,而是等待一段时间,因为调度策略认为,在等待的这一段时间内,可能会有另一个读请求,将读请求积攒在一起总比来来去去要好,AS调度策略的要点在于到底是否要等待以及等待多久,这些都是按照对进程的统计完成的,算法很复杂,然而思想却很简单,一个不得不做的读请求完成以后,IO调度器在一段时间内等待“相邻”读请求的到来,随着预测得到的等待时间的增长,“相邻”的概念范围越来越宽,并且也能加进来一些写请求,最终如果这个相邻的概念已经扩展到了整个磁盘,那么AS算法也就退化成了deadline算法。实质上,AS算法就是摆脱了deadline算法的弊端,它的弊端就是磁头可能来回移动从而降低了吞吐量,而deadline算法是摆脱了linus电梯的弊端,它的弊端就是会引起饥饿,总而言之,吞吐量和磁头寻道紧密相连,它和饥饿是一对冤家,需要权衡!



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1274077

相关文章
|
1月前
|
存储 缓存 安全
Java 中 IO 流、File文件
Java 中 IO 流、File文件
|
17天前
|
Java Unix Windows
|
2天前
|
Java 开发者
Java一分钟之-Java IO流:文件读写基础
【5月更文挑战第10天】本文介绍了Java IO流在文件读写中的应用,包括`FileInputStream`和`FileOutputStream`用于字节流操作,`BufferedReader`和`PrintWriter`用于字符流。通过代码示例展示了如何读取和写入文件,强调了常见问题如未关闭流、文件路径、编码、权限和异常处理,并提供了追加写入与读取的示例。理解这些基础知识和注意事项能帮助开发者编写更可靠的程序。
9 0
|
6天前
|
存储 缓存 Java
Java IO 流详解
Java IO 流详解
16 1
|
12天前
|
存储 Java
java IO接口(Input)用法
【5月更文挑战第1天】Java的`java.io`包包含多种输入输出类。此示例展示了如何使用`FileInputStream`从`input.txt`读取数据。首先创建`FileInputStream`对象,接着创建一个字节数组存储读取的数据,调用`read()`方法将文件内容填充至数组。然后将字节数组转换为字符串并打印,最后关闭输入流。注意,`InputStream`是抽象类,此处使用其子类`FileInputStream`。其他子类如`ByteArrayInputStream`、`ObjectInputStream`和`BufferedInputStream`各有特定用途。
21 2
|
13天前
|
存储 Java Linux
【Java EE】 文件IO的使用以及流操作
【Java EE】 文件IO的使用以及流操作
|
18天前
|
存储 Java 数据库
[Java 基础面试题] IO相关
[Java 基础面试题] IO相关
|
18天前
|
缓存 Java API
Java NIO和IO之间的区别
NIO(New IO),这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
16 1
|
21天前
|
Java
Java基础教程(12)-Java中的IO流
【4月更文挑战第12天】Java IO涉及输入输出,包括从外部读取数据到内存(如文件、网络)和从内存输出到外部。流是信息传输的抽象,分为字节流和字符流。字节流处理二进制数据,如InputStream和OutputStream,而字符流处理Unicode字符,如Reader和Writer。File对象用于文件和目录操作,Path对象简化了路径处理。ZipInputStream和ZipOutputStream则用于读写zip文件。