Linux 的 IO 子系统由 VFS(Virtual File System,虚拟文件系统)层和块层构成。 其中 VFS 层用于将各种不同的文件系统统一起来,形成统一的抽象层。 而块层用于通过设备驱动将数据读取或写入物理磁盘。

我们通常说的 文件系统的块大小,指的就是块层中的设备驱动程序从物理磁盘读取/写入数据的最小单位。
值得一提的是,当分区的大小不为块大小的整数时(比如在512字节扇区的磁盘上,文件系统块大小设置为为4K,而分区不是8的整数倍时),那么最终会有一个块超出分区界限,那么这个超出分区界限的块不会在文件系统中被使用。
当写入数据时,根据上图所示,其步骤为:
当读取数据时,根据上图所示,其步骤为:

当文件系统通过 IO 调度器将数据写入物理磁盘时,遵循以下步骤:
Linux 主要使用以下四种 IO 调度器,它们的特征如下:
我们可以通过 /sys/block/<磁盘名>/queue/scheduler 来查看或设置 IO 调度器的名称。
cat /sys/block/sda/queue/scheduler
结果为:
noop deadline [cfq]
这个意思是,本机支持的调度器有 noop, deadline 和 cfq,其中 sda 中采取的调度器为 cfg(被[]括起来),此外我们也能通过 lsblk -t 命令来查看调度器
lsblk -t
结果为:
NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED RQ-SIZE RA WSAME
sda 0 512 0 512 512 0 cfq 128 128 0B
├─sda1 0 512 0 512 512 0 cfq 128 128 0B
├─sda2 0 512 0 512 512 0 cfq 128 128 0B
└─sda3 0 512 0 512 512 0 cfq 128 128 0B
sr0 0 512 0 512 512 1 cfq 128 128 0B
其中 SCHED 这一栏中现实的就是当前调度器的名称。
通过 echo 命令往 /sys/block/<磁盘名>/queue/scheduler 中写入新的 IO 调度器名称就能够临时修改当前使用的调度器。
sudo bash -c 'echo "deadline" > /sys/block/sda/queue/scheduler'
cat /sys/block/sda/queue/scheduler
结果为:
noop [deadline] cfq
可以看到,调度器被修改为 deadline 了,我们再用 lsblk 验证一下:
lsblk -t
结果为:
NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED RQ-SIZE RA WSAME
sda 0 512 0 512 512 0 deadline 128 128 0B
├─sda1 0 512 0 512 512 0 deadline 128 128 0B
├─sda2 0 512 0 512 512 0 deadline 128 128 0B
└─sda3 0 512 0 512 512 0 deadline 128 128 0B
sr0 0 512 0 512 512 1 cfq 128 128 0B
通过 ionice 命令可以对 cfq 调度器中的每个进程设置优先级:
此外,对于 Real time 和 Best effort 的进程,还能指定数值 0~7 的优先级参数,数值越小,优先级越高。
关于 ionice 的用法,可以查看帮助
ionice --help
结果为:
用法:
ionice [选项] -p <pid>...
ionice [选项] -P <pgid>...
ionice [选项] -u <uid>...
ionice [选项] <命令>
设置或更改进程的 IO 调度类别和优先级。
选项:
-c, --class <类别> 调度类别的名称或数值
0: 无, 1: 实时, 2: 尽力, 3: 空闲
-n, --classdata <数字> 指定调度类别的优先级(0..7),只针对
“实时”和“尽力”类别
-p, --pid <pid>... 对这些已运行的进程操作
-P, --pgid <pgrp>... 对这些组中已运行的进程操作
-t, --ignore 忽略失败
-u, --uid <uid>... 对属于这些用户的已运行进程操作
-h, --help display this help
-V, --version display version
更多信息请参阅 ionice(1)。
