Linux中常见IO调度器
单队列调度算法 | 多队列调度算法 |
---|---|
deadline | mqdeadlines |
cfq | bfq |
noop | none |
kyber |
对于磁盘I/O,Linux提供了cfq, deadline和noop三种调度策略
- cfq: 这个名字是Complete Fairness Queueing的缩写,它是一个复杂的调度策略,按进程创建多个队列,试图保持对多个进程的公平(这就没考虑读操作和写操作的不同耗时)
- deadline: 这个策略比较简单,只分了读和写两个队列(这显然会加速读取量比较大的系统),叫这个名字是内核为每个I/O操作都给出了一个超时时间
- noop: 这个策略最简单,只有单个队列,只有一些简单合并操作
考虑到硬件配置、实际应用场景(读写比例、顺序还是随机读写)的差异,上面的简单解释对于实际选择没有太大帮助,实际该选择哪个基本还是要实测来验证。不过下面几条说明供参考:
- 根据多篇文章的说法,deadline和noop差异不是太大,但它们俩与cfq差异就比较大
- MySQL这类数据存储系统不要使用cfq(时序数据库可能会有所不同。不过也有说从来没见过deadline比cfq差的情况)
- 对于虚拟机上面的磁盘,建议采用比较简单的noop,毕竟数据实际上怎么落盘取决于虚拟化那一层
Noop调度器算法(SSD)
NOOP全称No Operation,中文名称电梯式调度器,该算法实现了最简单的FIFO队列,所有I/O请求大致按照先来后到的顺序进行操作。NOOP实现了一个简单的FIFO队列,它像电梯的工作方式一样对I/O请求进行组织。它是基于先入先出(FIFO)队列概念的 Linux 内核里最简单的I/O 调度器。此调度程序最适合于固态硬盘。
echo noop > /sys/block/sdb/queue/scheduler
Deadline调度器算法(读优先)
-
Linus Elevator
在2.4 内核中它是第一种I/O调度器。它的主要作用是为每个设备维护一个查询请求,当内核收到一个新请求时,如果能合并就合并。如果不能合并,就会尝试排序。如果既不能合并,也没有合适的位置插入,就放到请求队列的最后。
Deadline翻译成中文是截止时间调度器,是对Linus Elevator的一种改进,它避免有些请求太长时间不能被处理。另外可以区分对待读操作和写操作。DEADLINE额外分别为读I/O和写I/O提供了FIFO队列。
Deadline对读写request进行了分类管理,并且在调度处理的过程中读请求具有较高优先级。这主要是因为读请求往往是同步操作,对延迟时间比较敏感,而写操作往往是异步操作,可以尽可能的将相邻访问地址的请求进行合并,但是,合并的效率越高,延迟时间会越长。因此,为了区别对待读写请求类型,deadline采用两条链表对读写请求进行分类管理。但是,引入分类管理之后,在读优先的情况下,写请求如果长时间得到不到调度,会出现饿死的情况,因此,deadline算法考虑了写饿死的情况,从而保证在读优先调度的情况下,写请求不会被饿死。
总体来讲,deadline算法对request进行了优先权控制调度,主要表现在如下几个方面:
读写请求分离,读请求具有高优先调度权,除非写请求即将被饿死的时候,才会去调度处理写请求。这种处理可以保证读请求的延迟时间最小化。
对请求的顺序批量处理。对那些地址临近的顺序化请求,deadline给予了高优先级处理权。例如一个写请求得到调度后,其临近的request会在紧接着的调度过程中被处理掉。这种顺序批量处理的方法可以最大程度的减少磁盘抖动。
保证每个请求的延迟时间。每个请求都赋予了一个最大延迟时间,如果达到延迟时间的上限,那么这个请求就会被提前处理掉,此时,会破坏磁盘访问的顺序化特征,回影响性能,但是,保证了每个请求的最大延迟时间。
echo deadline > /sys/block/sdb/queue/scheduler
cfq(读写公平)
CFQ全称Completely Fair Scheduler ,中文名称完全公平调度器,它是现在许多 Linux 发行版的默认调度器,CFQ是内核默认选择的I/O调度器。它将由进程提交的同步请求放到多个进程队列中,然后为每个队列分配时间片以访问磁盘。对于通用的服务器是最好的选择,CFQ均匀地分布对I/O带宽的访问。CFQ为每个进程和线程,单独创建一个队列来管理该进程所产生的请求,以此来保证每个进程都能被很好的分配到I/O带宽,I/O调度器每次执行一个进程的4次请求。该算法的特点是按照I/O请求的地址进行排序,而不是按照先来后到的顺序来进行响应。简单来说就是给所有同步进程分配时间片,然后才排队访问磁盘。
echo cfq > /sys/block/sdb/queue/scheduler
none (Multiqueue)
多队列无操作I / O调度程序。不对请求进行重新排序,最小的开销。NVME等快速随机I / O设备的理想选择。
mq-deadline(多队列)
这是对最后期限I / O调度程序的改编,但设计用于 多队列设备。一个出色的多面手,CPU开销相当低。
I/O调度器的选择
-
Deadline
适用于大多数环境,特别是写入较多的文件服务器,从原理上看,DeadLine是一种以提高机械硬盘吞吐量为思考出发点的调度算法,尽量保证在有I/O请求达到最终期限的时候进行调度,非常适合业务比较单一并且I/O压力比较重的业务,比如Web服务器,数据库应用等。
-
CFQ
为所有进程分配等量的带宽,适用于有大量进程的多用户系统,CFQ是一种比较通用的调度算法,它是一种以进程为出发点考虑的调度算法,保证大家尽量公平,为所有进程分配等量的带宽,适合于桌面多任务及多媒体应用。
-
NOOP
对于闪存设备和嵌入式系统是最好的选择。对于固态硬盘来说使用NOOP是最好的,DeadLine次之,而CFQ效率最低。
测试磁盘读写
echo noop|cfq|deadline > /sys/block/sda/queue/scheduler
# 测试磁盘读写
time dd if=/dev/sda1 of=/tmp/test bs=2M count=300 conv=fdatasync
# 结果,在读写测试场景下的结果是:
第一,deadline: 用时3.06569s,速度 68.5 MB/s
第二,cfq:用时3.34928s,速度62.7 MB/s
第三,noop:用时3.38164s,速度62.1 MB/s
# 测试磁盘只读操作
time dd if=/dev/sda1 of=/dev/null bs=2M count=300
# 结果,在只读测试场景下的结果是:
第一,noop: 用时1.4871s,速度 141.2 MB/s
第二,deadline:用时1.59658s, 速度131.5 MB/s
第三,cfq:用时1.61414s, 130.1 MB/s
# 测试磁盘写操作
time dd if=/dev/zero of=/tmp/test bs=2M count=300 conv=fdatasync
# 结果,在写测试场景下的结果是:
第一,deadline:用时0.9383s,速度 223.8 MB/s
第二,cfq: 用时1.03042s, 速度203.8 MB/s
第三,noop:用时1.21247s, 速度173.2 MB/s