0%

磁盘IO调度策略

Linux 的文件 IO 子系统是 Linux 中最复杂的一个子系统(没有之一)。

下图来源

目前Linux系统中的I/O调度策略有4种,分别为(默认为CFQ):

  • NOOP
  • CFQ(默认)
  • DeadLine
  • Anticipatory(被删除)

NOOP

NOOP 全称 No Operation,该算法实现了最简单的 FIFO 队列,所有 IO 请求大致按照先来后到的顺序进行操作。之所以说“大致”,原因是 NOOP 在 FIFO 的基础上还做了相邻 IO 请求的合并,并不是完全按照先进先出的规则满足I/O请求。

假设有如下的 IO 请求序列:

1
100 500 101 10 56 1000

NOOP 将会按照如下顺序满足 IO 请求:

1
100(101) 500 10 56 1000

CFQ

CFQ 全称 Completely Fair Queuing,该算法的特点是按照I/O请求的地址进行排序进行响应。

CFQ 是默认的磁盘调度算法,它试图均匀地分布对 IO 带宽的访问,对于通用服务器来说是最好的选择。

CFQ 为每个进程单独创建一个队列来管理该进程所产生的请求。每个进程一个队列,各队列之间的调度使用时间片进行调度,以此来保证每个进程都能被很好地分配到 IO 带宽。IO 调度器每次执行一个进程的4次请求。在传统的SAS盘上,磁盘寻道花去了绝大多数的 IO 响应时间。

CFQ 的出发点是对 IO 地址进行排序,以尽量少的磁盘旋转次数来满足尽可能多的 IO 请求。在 CFQ 算法下,SAS盘的吞吐量大大提高了。相比于 NOOP 的缺点是,先来的 IO 请求并不一定能被满足,可能会出现“饿死”的情况。(这里应该说:CFQ试图均匀地分布对I/O带宽的访问,避免进程被饿死并实现较低的延迟,是deadline和as调度器的折中)

假设有如下的 IO 请求序列:

1
100 500 101 10 56 1000

CFQ 将会按照如下顺序满足:(注意下面只有前4个IO请求进行了排序)

1
100 101 500 1000 10 56

DeadLine

DeadLine 在 CFQ 的基础上,解决了 IO 请求“饿死”的极端情况

除了 CFQ 本身具有的 IO 排序队列,DeadLine 额外分别为读 IO 和写 IO 提供了FIFO队列。读FIFO队列的最大等待时间为500ms,写FIFO队列的最大等待时间为5s。FIFO队列内的 IO 请求优先级要比 CFQ 队列中的高,而读FIFO队列的优先级又比写FIFO队列的优先级高。优先级可以表示如下:

1
FIFO(read) > FIFO(write) > CFQ

Anticipatory

Anticipatory 在 DeadLine 的基础上,为每个读I/O都设置了6ms的等待时间窗口。如果在6ms内收到了相邻位置的读I/O请求,就可以立即满足。

Anticipatory 算法通过增加等待时间来获得更高的性能,假设一个块设备只有一个物理查找磁头(例如一个单独的SATA硬盘),将多个随机的小写入流合并成一个大写入流(相当于将随机读写变顺序读写),通过这个原理来使用读取/写入的延时换取最大的读取/写入吞吐量。

Anticipatory 算法从Linux 2.6.33版本后被删除了,因为使用 CFQ 通过配置也能达到 Anticipatory 的效果。

小结

Linux I/O调度器是 Linux 内核中的一个组成部分,用户可以通过根据不同的存储器来设置 Linux I/O 调度器从而达到优化系统性能。通常来说:

  • NOOP 调度器适用于固态硬盘
  • CFQ 调度器适用于桌面多任务及媒体应用
  • DeadLine 调度器适用于写入较多的文件服务器,比如Web服务器,数据库应用

相关命令

1
2
3
4
# 查看磁盘的IO调度策略,注意:其中sda是硬盘名
cat /sys/block/sda/queue/scheduler
# 设置IO调度策略为 cfq
echo cfq > /sys/block/sda/queue/scheduler
坚持原创技术分享,您的支持将鼓励我继续创作!