9.3 磁盘:实验与调优

9.7.5 利用率热力图

每个设备的利用率也可以显示为热力图,这样就可以识别设备利用率的平衡情况以及个别异常值 [Gregg 11b]。在这种情况下,百分比利用率位于 y 轴,颜色越深表示在该利用率级别的磁盘越多。这种热力图类型对于识别单块热点磁盘(包括“懒汉磁盘” sloth disks)非常有用,它们在热力图顶部(100%)表现为线条。关于利用率热力图的示例,请参见第 6 章,CPU,第 6.7.1 节,利用率热力图。

9.8 实验

本节介绍用于主动测试磁盘 I/O 性能的工具。关于应遵循的方法论,请参见第 9.5.9 节“微基准测试”。

实时监控建议

使用这些工具时,最好让 iostat(1) 持续运行,以便可以立即双重检查任何结果。某些微基准测试工具可能需要使用“直接”(direct)操作模式来绕过文件系统缓存,从而专注于磁盘设备性能。

9.8.1 临时测试

dd(1) 命令(设备到设备复制)可用于执行顺序磁盘性能的临时测试。例如,使用 1 Mbyte 的 I/O 大小测试顺序读取:

# dd if=/dev/sda1 of=/dev/null bs=1024k count=1k
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 7.44024 s, 144 MB/s

由于内核可以缓存和缓冲数据,dd(1) 测量到的吞吐量可能是缓存和磁盘的混合结果,而不仅仅是磁盘本身的。要仅测试磁盘的性能,您可以使用磁盘的字符特殊设备(character special device):在 Linux 上,raw(8) 命令(在可用的情况下)可以在 /dev/raw 下创建这些设备。顺序写入也可以类似地测试;但是,请注意这可能会破坏磁盘上的所有数据,包括主引导记录和分区表!

危险操作

直接对磁盘设备进行写入测试会破坏磁盘上的所有数据,包括主引导记录和分区表!请务必谨慎操作。

一种更安全的方法是将直接 I/O 标志与 dd(1) 和文件系统文件一起使用,而不是直接使用磁盘设备。请记住,现在的测试包含了一些文件系统的开销。例如,对一个名为 out1 的文件进行写入测试:

# dd if=/dev/zero of=out1 bs=1024k count=1000 oflag=direct
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 1.79189 s, 585 MB/s

另一个终端会话中的 iostat(1) 确认磁盘 I/O 写入吞吐量约为 585 Mbytes/sec。

对于输入文件的直接 I/O,请使用 iflag=direct

9.8.2 自定义负载生成器

为了测试自定义工作负载,您可以编写自己的负载生成器,并使用 iostat(1) 测量产生的性能。自定义负载生成器可以是一个简短的 C 程序,它打开设备路径并应用预期的工作负载。在 Linux 上,块特殊设备文件可以使用 O_DIRECT 打开,以避免缓冲。如果您使用高级语言,至少尽量使用避免库缓冲的系统级接口(例如 Perl 中的 sysread()),最好也能避免内核缓冲(例如 O_DIRECT)。

9.8.3 微基准测试工具

可用的磁盘基准测试工具包括,例如 Linux 上的 hdparm(8)

# hdparm -Tt /dev/sdb
/dev/sdb:
 Timing cached reads:   16718 MB in  2.00 seconds = 8367.66 MB/sec
 Timing buffered disk reads:  846 MB in  3.00 seconds = 281.65 MB/sec

-T 选项测试缓存读取,-t 测试磁盘设备读取。结果显示了磁盘缓存命中和未命中之间的巨大差异。

研究工具文档以了解任何注意事项,并参见第 12 章,基准测试,了解更多微基准测试的背景知识。另见第 8 章,文件系统,了解通过文件系统测试磁盘性能的工具(此类工具更多)。

9.8.4 随机读取示例

作为一个实验示例,我编写了一个自定义工具来对磁盘设备路径执行 8 Kbyte 的随机读取工作负载。同时运行了一到五个该工具的实例,并运行了 iostat(1)。包含零的写入列已被删除:

Device:    rrqm/s      r/s    rkB/s  avgrq-sz   aqu-sz r_await  svctm  %util
sda        878.00   234.00  2224.00     19.01     1.00    4.27   4.27 100.00
[...]
Device:    rrqm/s      r/s    rkB/s  avgrq-sz   aqu-sz r_await  svctm  %util
sda       1233.00   311.00  3088.00     19.86     2.00    6.43   3.22 100.00
[...]
Device:    rrqm/s      r/s    rkB/s  avgrq-sz   aqu-sz r_await  svctm  %util
sda       1366.00   358.00  3448.00     19.26     3.00    8.44   2.79 100.00
[...]
Device:    rrqm/s      r/s    rkB/s  avgrq-sz   aqu-sz r_await  svctm  %util
sda       1775.00   413.00  4376.00     21.19     4.01    9.66   2.42 100.00
[...]
Device:    rrqm/s      r/s    rkB/s  avgrq-sz   aqu-sz r_await  svctm  %util
sda       1977.00   423.00  4800.00     22.70     5.04   12.08   2.36 100.00

观察

注意 aqu-sz(平均队列大小)的阶梯式增加,以及 r_await 延迟的增加。

9.8.5 ioping

ioping(1) 是一个有趣的磁盘微基准测试工具,类似于 ICMP 的 ping(8) 实用程序。在 nvme0n1 磁盘设备上运行 ioping(1)

# ioping /dev/nvme0n1
4 KiB <<< /dev/nvme0n1 (block device 8 GiB): request=1 time=438.7 us (warmup)
4 KiB <<< /dev/nvme0n1 (block device 8 GiB): request=2 time=421.0 us
4 KiB <<< /dev/nvme0n1 (block device 8 GiB): request=3 time=449.4 us
4 KiB <<< /dev/nvme0n1 (block device 8 GiB): request=4 time=412.6 us
4 KiB <<< /dev/nvme0n1 (block device 8 GiB): request=5 time=468.8 us
^C
--- /dev/nvme0n1 (block device 8 GiB) ioping statistics ---
4 requests completed in 1.75 ms, 16 KiB read, 2.28 k iops, 8.92 MiB/s
generated 5 requests in 4.37 s, 20 KiB, 1 iops, 4.58 KiB/s
min/avg/max/mdev = 412.6 us / 437.9 us / 468.8 us / 22.4 us

默认情况下,ioping(1) 每秒发出一个 4 Kbyte 的读取请求,并以微秒为单位打印其 I/O 延迟。终止时会打印各种统计信息。

ioping(1) 与其他基准测试工具的不同之处在于其工作负载非常轻量。以下是 ioping(1) 运行时的一些 iostat(1) 输出:

$ iostat -xsz 1
[...]
Device             tps      kB/s    rqm/s   await aqu-sz  areq-sz  %util
nvme0n1           1.00      4.00     0.00    0.00   0.00     4.00   0.40

磁盘的利用率仅达到 0.4%。ioping(1) 有可能用于在生产环境中调试问题,而其他微基准测试工具则不合适,因为它们通常会将目标磁盘驱动到 100% 的利用率。

9.8.6 fio

灵活的 IO 测试器(fio)是一个文件系统基准测试工具,它也可以帮助了解磁盘设备的性能,特别是与 --direct=true 选项一起使用以采用非缓冲 I/O 时(当文件系统支持非缓冲 I/O 时)。它在第 8 章,文件系统,第 8.7.2 节,微基准测试工具中介绍过。

9.8.7 blkreplay

块 I/O 重放工具(blkreplay)可以重放使用 blktrace(第 9.6.10 节,blktrace)或 Windows DiskMon [Schöbel-Theuer 12] 捕获的块 I/O 负载。在调试难以用微基准测试工具重现的磁盘问题时,这可能非常有用。

关于如果目标系统发生改变,磁盘 I/O 重放可能会如何产生误导的示例,请参见第 12 章,基准测试,第 12.2.3 节,重放。


9.9 调优

第 9.5 节“方法论”中涵盖了许多调优方法,包括缓存调优、扩展和工作负载特征刻画,这些可以帮助您识别并消除不必要的工作。另一个重要的调优领域是存储配置,这可以作为静态性能调优方法论的一部分来研究。

以下各节展示了可以调优的区域:操作系统、磁盘设备和磁盘控制器。可用的可调参数因操作系统版本、磁盘型号、磁盘控制器及其固件的不同而异;请参阅它们各自的文档。虽然更改可调参数可能很容易做到,但默认设置通常是合理的,很少需要大量调整。

9.9.1 操作系统可调参数

这些包括 ionice(1)、资源控制(Resource Controls)和内核可调参数。

ionice

在 Linux 上,ionice(1) 命令可用于设置进程的 I/O 调度类和优先级。调度类用数字标识:

  • 0, none:未指定类,因此内核将选择一个默认值——尽力而为(best effort),其优先级基于进程的 nice 值。
  • 1, real-time:最高优先级的磁盘访问。如果滥用,这可能会使其他进程饥饿(就像 RT CPU 调度类一样)。
  • 2, best effort:默认调度类,支持优先级 0–7,其中 0 为最高。
  • 3, idle:仅在一个磁盘空闲的宽限期之后才允许磁盘 I/O。

示例用法:

# ionice -c 3 -p 1623

这会将进程 ID 1623 置于空闲 I/O 调度类中。这对于长时间运行的备份作业可能是理想的,因为它们不太可能干扰生产工作负载。

资源控制 (Resource Controls)

现代操作系统提供了以自定义方式管理磁盘或文件系统 I/O 使用情况的资源控制。

对于 Linux,控制组(cgroups)块 I/O(blkio)子系统为进程或进程组提供存储设备资源控制。这可以是比例权重(类似于份额)或固定限制。可以分别为读取和写入设置限制,并且可以针对 IOPS 或吞吐量(字节/秒)进行设置。有关更多详细信息,请参见第 11 章,云计算

可调参数 (Tunable Parameters)

Linux 可调参数示例包括:

  • /sys/block/*/queue/scheduler:用于选择 I/O 调度器策略:这些可能包括 noopdeadlinecfq 等。有关这些的早期描述,请参见第 9.4 节,架构。
  • /sys/block/*/queue/nr_requests:块层可以分配的读或写请求的数量。
  • /sys/block/*/queue/read_ahead_kb:文件系统请求的最大预读 Kbytes。

与其他内核可调参数一样,请检查文档以获取完整的列表、描述和警告。在 Linux 源代码中,请参阅 Documentation/block/queue-sysfs.txt

9.9.2 磁盘设备可调参数

在 Linux 上,hdparm(8) 工具可以设置各种磁盘设备可调参数,包括电源管理和降速(spindown)超时 [Archlinux 20]。使用此工具时要非常小心,并仔细研究 hdparm(8) man 手册页——各种选项被标记为“危险(DANGEROUS)”,因为它们可能导致数据丢失。

危险:数据丢失风险

hdparm(8) 的许多选项被标记为“DANGEROUS”,不当使用可能导致不可逆的数据丢失。修改磁盘设备参数前务必详细阅读 man 手册。

9.9.3 磁盘控制器可调参数

可用的磁盘控制器可调参数取决于磁盘控制器型号和供应商。为了让您了解这些可能包括的内容,以下显示了使用 MegaCli 命令查看的 Dell PERC 6 卡的一些设置:

# MegaCli -AdpAllInfo -aALL
[...]
Predictive Fail Poll Interval    : 300sec
Interrupt Throttle Active Count  : 16
Interrupt Throttle Completion    : 50us
Rebuild Rate                     : 30%
PR Rate                          : 0%
BGI Rate                         : 1%
Check Consistency Rate           : 1%
Reconstruction Rate              : 30%
Cache Flush Interval             : 30s
Max Drives to Spinup at One Time : 2
Delay Among Spinup Groups        : 12s
Physical Drive Coercion Mode     : 128MB
Cluster Mode                     : Disabled
Alarm                            : Disabled
Auto Rebuild                     : Enabled
Battery Warning                  : Enabled
Ecc Bucket Size                  : 15
Ecc Bucket Leak Rate             : 1440 Minutes
Load Balance Mode                : Auto
[...]

每个设置都有一个合理描述性的名称,并在供应商文档中有更详细的描述。

9.3 磁盘:实验与调优

文档连续性说明

本部分为文档的第 2/2 部分,承接上文关于磁盘控制器可调参数的内容。


9.10 练习

1. 回答以下关于磁盘术语的问题:

  • 什么是 IOPS
  • 服务时间(Service Time)和 等待时间(Wait Time)有什么区别?
  • 什么是磁盘 I/O 等待时间?
  • 什么是 延迟异常值(Latency Outlier)?
  • 什么是非数据传输磁盘命令?

2. 回答以下概念性问题:

  • 描述磁盘的利用率和饱和度。
  • 描述随机和顺序磁盘 I/O 之间的性能差异。
  • 描述磁盘内置缓存(on-disk cache)在读取和写入 I/O 中的作用。

3. 回答以下更深入的问题:

  • 解释为什么虚拟磁盘的利用率(忙碌百分比)可能会产生误导。
  • 解释为什么 “I/O wait”(I/O 等待)指标可能会产生误导。
  • 描述 RAID-0(条带化,striping)和 RAID-1(镜像,mirroring)的性能特征。
  • 描述当磁盘工作过载时会发生什么,包括对应用程序性能的影响。
  • 描述当存储控制器工作过载时(无论是吞吐量还是 IOPS 过载)会发生什么,包括对应用程序性能的影响。

4. 为您的操作系统开发以下流程:

  • 针对磁盘资源(磁盘和控制器)的 USE 方法 检查清单。包括如何获取每个指标(例如,执行哪个命令)以及如何解释结果。在安装或使用额外的软件产品之前,尽量使用现有的操作系统可观测性工具。
  • 针对磁盘资源的工作负载特征归纳检查清单。包括如何获取每个指标,并尽量优先使用现有的操作系统可观测性工具。

5. 仅根据以下 Linux iostat(1) 输出,描述可见的磁盘行为:

$ iostat -x 1
[...]
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           3.23    0.00   45.16   31.18    0.00   20.43
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              39.78 13156.99  800.00  151.61  3466.67 41200.00    93.88    
11.99    7.49    0.57   44.01   0.49  46.56
vdb               0.00     0.00    0.00    0.00     0.00     0.00     0.00     
0.00    0.00    0.00    0.00   0.00   0.00

提示:观察 iostat 各列指标

  • r/s, w/s: 每秒读写次数
  • rkB/s, wkB/s: 每秒读写千字节数
  • await, r_await, w_await: 平均 I/O 等待时间(毫秒)
  • svctm: 平均服务时间(毫秒)
  • %util: 磁盘利用率

6. (可选,高级)开发一个工具来跟踪除读和写之外的所有磁盘命令。

这可能需要在 SCSI 层面进行追踪。


9.11 参考文献