如何重现这些结果 - 重要细节

如何重现这些结果 - 重要细节
  1. sudo dd if=/dev/sda of=/dev/null bs=1M iflag=direct
  2. atopsar -d 5 # in a second terminal
  3. top # in a third terminal

由于。。。导致的结果atopsar

19:18:32  disk           busy read/s KB/read  writ/s KB/writ avque avserv _dsk_
...
19:16:50  sda             18%  156.5  1024.0     0.0     0.0   5.0   1.15 ms
19:16:55  sda             18%  156.3  1024.0     0.0     0.0   4.9   1.15 ms
...

为什么报告的磁盘利用率(“繁忙”)远低于 100%?

据 称top,该dd进程仅使用 CPU 的 3% 或更少。 还提供系统 CPU 的硬件和软件中断 (和) 使用率top的总体报告,显示低于 1%。我有四个 CPU(2 个核心,每个核心有 2 个线程)。hisi

/dev/sda是SATA硬盘。它不是 SSD,甚至不是混合 SSHD 驱动器。它的读取速度不能超过每秒 150 兆字节:-)。因此,这部分结果是有意义的:156 读取/秒 * 1024 KB/读取 = 156 MB/秒

内核版本是5.0.9-200.fc29.x86_64(Fedora Workstation 29)。 IO调度器是mq-deadline.从内核版本 5.0 开始,Fedora 使用多队列块层。因为单个队列块层已被删除:-)。

我相信 中的磁盘利用率数字atopsar -datop根据其中之一计算得出的内核 iostat 字段。链接的文档提到“字段 10 -- 执行 I/O 所花费的毫秒数”。还有一个更详细的定义,尽管我不确定它提到的函数是否仍然存在于多队列块层中。据我所知,和atopsar -datop使用通用代码sar -d读取此字段 10.(我相信//也使用此iostat -x字段mxiostat.py

附加测试

变体 2:更改为bs=512k,但保留iflag=direct.

dd if=/dev/sda of=/dev/null bs=512k iflag=direct

19:18:32  disk           busy read/s KB/read  writ/s KB/writ avque avserv _dsk_
...
19:18:00  sda             35%  314.0   512.0     0.0     0.0   2.1   1.12 ms
19:18:05  sda             35%  313.6   512.0     0.2     4.0   2.1   1.11 ms

变体 3:使用bs=1M,但删除iflag=direct.dd使用大约 10% CPU 和 35% 磁盘。

dd if=/dev/sda of=/dev/null bs=1M

19:18:32  disk           busy read/s KB/read  writ/s KB/writ avque avserv _dsk_
...
19:21:47  sda             35%  242.3   660.2     0.0     0.0   5.4   1.44 ms
19:21:52  sda             31%  232.3   667.8     0.0     0.0   9.5   1.33 ms

如何重现这些结果 - 重要细节

注意最后一个测试,即运行dd 没有 iflag=direct

这有点像猪。我看到它冻结了系统(鼠标光标)十秒或更长时间。即使我禁用了交换。 (测试将您的 RAM 填满增益/缓存。它正在填充非活动 LRU 列表。我认为周转会相对较快地驱逐不活动的缓存页面。同时,磁盘正忙于顺序读取,因此当您需要将某些内容分页时,需要花费更长的时间。这种情况有多糟糕可能取决于内核最终是否也会翻转活动 LRU 列表,或者将其缩小太多。即当前的情况如何“混合了许多不同的算法,并进行了一些修改以捕捉极端情况和各种优化”在你的情况下工作)。

精确的第一次测试的结果很难重现。

有时,KB/read显示为512而不是1024。在这种情况下,其他结果看起来更像是 的结果bs=512k。其中,它显示磁盘利用率约为 35%,而不是 20% 左右。无论哪种情况,我的问题都是成立的。

如果您想了解此行为,请参阅此处:为什么我的 IO 请求大小被限制为大约 512K?

答案1

这是内核版本 5.0 中的更改的结果:

块:删除part_round_stats和切换到不太精确的计数

我们想要转换为每个 cpu 的 in_flight 计数器。

函数part_round_stats每个jiffy都需要in_flight计数器,每个jiffy对所有percpu变量求和的成本太高,所以必须删除它。 part_round_stats 用于计算两个计数器 - time_in_queue 和 io_ticks。

time_in_queue 可以在没有part_round_stats 的情况下计算,通过添加I/O 结束时I/O 的持续时间(该值几乎与之前计算的值一样精确,除了不计算正在进行的I/O 的时间)。

io_ticks 可以通过在 I/O 开始或结束且 jiffies 值发生变化时增加该值来近似。如果 I/O 花费的时间少于一瞬间,则该值与之前计算的值一样精确。如果 I/O 花费的时间超过一瞬间,io_ticks 可能会漂移到先前计算的值之后。

(io_ticks用于部分统计显示(),提供内核IO统计对于“字段 10 -- 执行 I/O 所花费的毫秒数”。)

这很好地解释了我的结果。在 Fedora 内核配置中,“瞬间“是 1 毫秒。我预计提交的大型读取 IOdd可能会等待超过一两个 jiffies。特别是在我的系统上,它使用老式机械 HDD。

当我返回到之前的内核系列 4.20.x 时,它显示了正确的磁盘利用率:

$ uname -r
4.20.15-200.fc29.x86_64
$ atopsar -d 5
...
13:27:19  disk           busy read/s KB/read  writ/s KB/writ avque avserv _dsk_
13:28:49  sda             98%  149.4  1024.0    13.0     5.3   2.2   6.04 ms
13:28:54  sda             98%  146.0  1024.0     7.2     5.7   1.5   6.38 ms

cfq这个旧内核默认使用传统的单队列块层和IO 调度程序。使用IO调度器时结果也是一样的deadline


更新:从内核 5.7 开始,这个近似值被调整。问题中的命令再次显示磁盘利用率为 100%。对于一些更复杂的工作负载,新的近似值预计会崩溃(尽管我还没有注意到)。

block/diskstats:慢速磁盘的 io_ticks 更准确的近似值

目前,如果 jiffies 计数器已更改,则 io_ticks 的近似值是在请求的每个开始和结束处加一。这对于短于一瞬间的请求或者其中一个请求在每一瞬间开始/结束的情况来说非常有效。

如果磁盘一次只执行一个请求,并且它们长于两个 jiffies,则仅计算第一个和最后一个 jiffies。

修复很简单:在请求结束时,将自上次更新以来传递的 io_ticks jiffy 添加到 io_ticks 中,而不仅仅是一个 jiffy。

示例:普通硬盘执行随机读取 4k 请求的时间约为 12ms。

fio --name=test --filename=/dev/sdb --rw=randread --direct=1 --runtime=30 & iostat -x 10 sdb

注意补丁前后 iostat 的“%util”8,43% -> 99,99% 的变化:

前:

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sdb               0,00     0,00   82,60    0,00   330,40     0,00     8,00     0,96   12,09   12,09    0,00   1,02   8,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
sdb               0,00     0,00   82,50    0,00   330,00     0,00     8,00     1,00   12,10   12,10    0,00  12,12  99,99

现在 io_ticks 不会减少请求开始和结束之间的时间,但对于队列深度 > 1 ,相邻开始之间的一些 I/O 时间可能会丢失。

对于负载估计,“%util”不如平均队列长度有用,但它清楚地显示磁盘队列完全为空的频率。

修复:5b18b5a(“阻止:删除part_round_stats并切换到不太精确的计数”)
签署人:Konstantin Khlebnikov <[电子邮件受保护]>
审稿人:雷鸣 <[电子邮件受保护]>
签署人:Jens Axboe <[电子邮件受保护]>

相关内容