您的位置:首页 > 运维架构 > Linux

Linux I/O调度程序

2015-12-14 00:18 302 查看
Linux I/O调度程序是块设备I/O子系统的主要组件,它介于通用块层和块设备驱动程序之间,如图所示:



当Linux内核组件要读写一些数据时,并不是请求一发出,内核便立即执行该请求,而是把它放到设备的I/O等待队列中,并通过算法在队列中合并多个相邻的请求,然后发送到块设备驱动程序中。在数据返回后,把数据分别返回给相应的请求。在2.6内核中,实现了四种I/O调度算法,分别为预期(Anticipatory)算法、最后期限(Deadline)算法、完全公平队列(CFQ,Completely
Fair Queuing)算法以及NOOP算法(No Operation)。可以在内核引导时指定一种I/O调度算法,也可以在运行时通过sysfs文件系统/sys/block/sda/queue/scheduler来为块设备定制一个特定的I/O调度算法或查看块设备目前所使用的I/O调度算法。

CFQ(Completely Fair Queuing 完全公平的排队)(elevator = cfq):这是默认算法,它试图在多个应用程序间均匀地分布对I/O宽带的访问。为了实现这种目标,算法为每一个应用程序维护一个排序的请求队列,并且周期性使用轮询的方法扫描这些队列。一旦发现一个非空的进程请求队列,就把这个队列的一批请求放入发送队列的尾部。

Deadline(elevator = deadline):其核心就是在传统的电梯算法中加入请求超时机制。该机制主要包括两点:1 请求超时时,优先响应超时请求;2 请求没有超时时,顺序服务排序队列。这个算法试图把每次请求的延迟降至最低。该算法通过重排请求的顺序来提高性能。Deadline算法维护5个队列,除了请求发送队列以外,还是用了4个队列。其中两个排序队列分别包含读请求和写请求,这个队列是按照起始扇区数来排序的。另外两个最后期限队列包含相同的读请求和写请求,只不过它们是根据其“最后期限”排列的。这两个队列的目的是为了避免请求“饿死”。因为电梯策略优先处理与上一个处理请求最近的请求,因而就会对某个请求忽略很长一段时间,这时就会发生“饿死”的情况。请求的随后期限本质上就是超时定时器,当请求被传给电梯算法时开始计时。缺省情况下,Deadline算法读请求优先于写请求,因为读请求通常阻塞发出请求的进程。最后期限保证了调度程序照顾等待很长一段时间的那个请求,即使它位于排序队列的末尾。

NOOP(elevator = noop):这个算法实现了一个简单FIFO队列,它假定I/O请求由驱动程序或者设备做了优化或者重排了顺序(就像一个智能控制器完成的工作那样)。在有些SAN环境下,这个选择可能是最好的选择。

Anticipatory(elevator = as):相对Linux其他的调度算法,这个算法是最为复杂的。它是deadline算法的一个改进。和deadline算法一样,有两个deadline队列和两个排序队列,I/O调度程序扫描程序队列,在读请求和写请求间交替执行,但倾向于执行读请求。如果没有请求过期,则扫描过程是顺序的。缺省的读失效时间为125ms,而写失效时间为250ms。除此之外,Anticipatory算法使用一些启发式方法。在一些情况下,电梯算法可以选择响应在当前磁头位置后面的请求,它强制磁头回头。这种情况发生在磁头的向前寻道距离是向后距离的一半以上。算法收集关于每个进程队列的I/O操作的统计信息,在发送一个来自于进程P的读请求之后,算法检测是否有来自于同一个进程的下一个请求,如果有就立即发送,否则算法搜集来自于这个进程的统计信息。如果P有可能很快发送一个请求,那么算法等待一小段时间(缺省值是7ms)。因此算法可以预测来自于进程P的读请求是否是“接近”当前发送的请求。一般而言,对于桌面工作站来说,这个算法可能是一个不错的选择,但对服务器则没有理想的作用。

从书中看到的,觉得有用就记下来了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: