sudo dd if=/dev/sda of=/dev/null bs=1M iflag=directatopsar -d 5 # in a second terminaltop # 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
...
Run Code Online (Sandbox Code Playgroud)
为什么报告的磁盘利用率(“忙”)远低于 100%?
据top,该dd进程仅使用 3% 或更少的 CPU。 top还提供系统 CPU 的硬件和软件中断 (hi和si) 使用情况的总体报告,显示低于 1%。我有四个 CPU(2 个内核,每个内核 2 个线程)。
/dev/sda是SATA硬盘。它不是 SSD,甚至不是混合 SSHD 驱动器。它的读取速度不能超过每秒 150 兆字节 :-)。所以这部分结果是有意义的:156 read/s * 1024 KB/read = 156 MB/s
内核版本是5.0.9-200.fc29.x86_64(Fedora Workstation 29)。IO 调度程序是mq-deadline. 从内核版本 5.0 开始,Fedora 使用多队列块层。因为单个队列块层已被删除:-)。
我相信,磁盘利用率图中atopsar -d,并atop从一个计算内核iostat的领域。链接的文档提到了“字段 10 -- 花费在 I/O 上的毫秒数”。还有一个更详细的定义,虽然我不确定它提到的功能是否仍然存在于多队列块层中。据我所知,双方atopsar -d并atop使用通用代码阅读本场10(我相信本场也使用sar -d/ 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
Run Code Online (Sandbox Code Playgroud)
变体 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
Run Code Online (Sandbox Code Playgroud)
dd iflag=direct这有点像猪。我看到它冻结系统(鼠标光标)十秒钟或更长时间。即使我禁用了交换。(测试用buff/cache填充你的 RAM 。它正在填充非活动的 LRU 列表。我认为周转率会相对较快地驱逐非活动的缓存页面。同时,磁盘忙于顺序读取,所以当你需要时需要更长的时间将某些内容分页。这可能取决于内核最终是否也翻转了活动的 LRU 列表,或者将其缩小太多。即当前“许多不同算法的混合效果如何,并对其进行了大量修改”捕捉角落案例和各种优化”适用于您的案例)。
有时,KB/read显示为512而不是1024。在这种情况下,其他结果看起来更像是来自 的结果bs=512k。包括它显示大约 35% 的磁盘利用率,而不是大约 20%。我的问题在任何一种情况下都成立。
如果您想了解这种行为,请在此处进行描述:为什么我的 IO 请求的大小被限制为大约 512K?
这是内核版本 5.0 更改的结果:
阻止:删除 part_round_stats 并切换到不太精确的计数
我们想转换为 per-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在part_stat_show() 中使用,为“字段 10 -- 执行 I/O 所花费的毫秒数”提供内核 IO 统计信息。)
这很好地解释了我的结果。在 Fedora 内核配置中,“ jiffy ”是 1 毫秒。我预计提交的大型读取 IOdd可能会等待超过一两个 jiffies。特别是在我的系统上,它使用老式机械硬盘。
当我回到之前的内核系列 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
Run Code Online (Sandbox Code Playgroud)
这个旧内核cfq默认使用传统的单队列块层和IO 调度程序。使用deadlineIO调度器时,结果也是一样的。
更新:从内核 5.7 开始,调整了这个近似值。问题中的命令再次显示 100% 磁盘利用率。对于一些更复杂的工作负载,新的近似值预计会失效(尽管我还没有注意到)。
block/diskstats:对于慢速磁盘更准确地近似 io_ticks
如果 jiffies 计数器发生变化,当前 io_ticks 通过在请求的每个开始和结束处添加一个来近似。这适用于短于 jiffy 的请求,或者如果其中一个请求在每个 jiffy 开始/结束。
如果磁盘一次只执行一个请求并且它们比两个 jiffies 长,那么只会计算第一个和最后一个 jiffies。
修复很简单:在请求结束时加起来自上次更新以来传递的 io_ticks jiffy 而不是一个 jiffy。
示例:普通硬盘在 12ms 左右执行随机读取 4k 请求。
fio --name=test --filename=/dev/sdb --rw=randread --direct=1 --runtime=30 &iostat -x 10 sdb注意 iostat 的 "%util" 8,43% -> 99,99% 补丁前后的变化:
前:
Run Code Online (Sandbox Code Playgroud)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后:
Run Code Online (Sandbox Code Playgroud)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 <khlebnikov@yandex-team.ru>
审核人:Ming Lei <ming.lei@redhat.com>
签字-off-by: Jens Axboe <axboe@kernel.dk>
| 归档时间: |
|
| 查看次数: |
1363 次 |
| 最近记录: |