这篇文章上次修改于 765 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

文件系统是对存储设备上的文件进行统一管理的一种机制。Linux 在各种文件系统的基础上又抽象了一层虚拟文件系统 VFS。

VFS 内部通过超级块、逻辑块、索引节点和目录项等数据结构管理文件。其中,目录项是一个内存缓存,而超级块、逻辑块和索引节点是存储在磁盘上的。

1 磁盘

将磁盘按照存储介质分类:

  • 机械盘,缩写为 HDD(Hard Disk Driver),由磁头和盘片组成,数据存储在环状磁道中。读写数据前,需将磁头定位到数据所在的磁道。随机 I/O 会导致磁头不断移动,读写速度较慢。
  • 固态磁盘,缩写为 SSD(Solid State Disk),由固态电子元器件组成。因为不需要磁道寻址,所以性能比机械盘好。但也存在“先擦除再写入“的限制,所以随机 I/O 性能同样比连续 I/O 差。

按照使用方式,可分为多种架构:

  • 直接作为独立磁盘设备使用。往往还会根据需要,划分为不同的逻辑分区,如 /dev/sda 可划分为 /dev/sda1 和 /dev/sda2。
  • 将多个磁盘组合为一个逻辑磁盘,构成冗余独立磁盘阵列,即 RAID,可提高数据的访问性能和可靠性。

Linux 中,磁盘是作为块设备来管理的。拥有主设备号和次设备号,主设备号用来区分设备类型,次设备号区分同种设备。

2 通用块层

Linux 通过通用块层管理不同的块设备。

通用块层是位于磁盘驱动和文件系统之间的块设备抽象层。是磁盘 I/O 的核心。

它的功能包括:

  • 提供统一接口,屏蔽细节。向上,为文件系统和应用程序提供访问设备的统一接口;向下,将各种异构的磁盘设备抽象为统一的块设备,并提供统一的框架管理这些设备的驱动程序。
  • 将文件系统和应用程序的 I/O 请求排序,通过重新排序、请求合并等方式提高磁盘读写效率。

对 I/O 排序即为 I/O 调度,包括四种:

  • NONE
  • NOOP,先进先出,只对 I/O 请求进行基本的合并。
  • CFQ(Completely Fair Scheduler),为每个进程维护了一个 I/O 调度队列,并按照时间片均匀分布每个进程的 I/O 请求。还支持优先级调整,适用于运行大量进程的系统,如桌面环境、多媒体应用等。
  • Deadline,分别为读、写请求创建不同的 I/O 队列,可提高机械盘的吞吐量。适用于 I/O 压力比较重的场景,如数据库等。

3 I/O 栈

由上到下分为文件系统层、通用块层和设备层。

为了优化文件系统层访问性能,会使用页缓存、索引节点缓存、目录项缓存等多种缓存机制。

为了优化块设备访问性能,会使用缓冲区。

4 磁盘性能指标

包括五个指标:

  • 使用率,磁盘处理 I/O 的时间百分比,超过 80% 时存在性能瓶颈。
  • 饱和度,磁盘处理 I/O 的繁忙程度,达到 100% 时无法处理新的 I/O 请求。
  • IOPS,每秒 I/O 请求数。在数据库、大量小文件等随机读写量大的场景中更能反应系统性能。
  • 吞吐量,每秒 I/O 请求大小。在多媒体等顺序读读场景中更能反应系统性能。
  • 响应时间,I/O 请求从发出到收到响应的间隔时间。

测试磁盘性能方式:不同 I/O 大小(一般是 512B 至 1MB 中间的若干值)分别在随机读、顺序读、随机写、顺序写等各种场景下的性能情况。

5 磁盘 I/O 观测

每块磁盘使用情况:

$ iostat -d -x 1
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
vda               0.00     3.31    0.03    2.65     1.48    27.25    21.49     0.00    1.53    2.87    1.52   0.22   0.06
scd0              0.00     0.00    0.00    0.00     0.00     0.00     7.11     0.00    0.60    0.60    0.00   0.60   0.00
  • r/s,w/s,每秒发送给磁盘的读、写请求数。
  • rrqm/s,wrqm/s,每秒合并的读、写请求数。
  • r_wait,w_ait,读、写请求处理完成等待时间,单位毫秒,包括队列中的等待时间和设备实际处理时间。
  • %util,磁盘处理 I/O 的时间百分比,即使用率。

以上指标中:

  • %util 为磁盘 I/O 使用率
  • r/s + w/s 为 IOPS
  • rkB/s + wkB/s 为吞吐量
  • r_wait + w_ait 为响应时间

6 进程 I/O 观测

$ pidstat -d 1
22时41分22秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  iodelay Command
22时41分23秒     0     29062      0.00      4.00      0.00        0 YDService
  • kB_ccwr/s,每秒取消的写请求数据大小。
  • iodelay,块 I/O 延迟,包括等待同步块 I/O 和换入块 I/O 结束的时间,单位是时钟周期。

iotop 可按照 I/O 大小对进程排序:

$ iotop
Total DISK READ :       0.00 B/s | Total DISK WRITE :       7.85 K/s 
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s 
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND 
15055 be/3 root        0.00 B/s    7.85 K/s  0.00 %  0.00 % systemd-journald 

参考

倪朋飞. Linux 性能优化实战.