我注意到,当我查看输出时,/proc/diskstats读取的总时间、写入的总时间和执行 IO 的总时间之间存在差异。例如,我看到一个条目/proc/diskstats是:
$ cat /proc/diskstats
...
8 0 sda 944150584 590524 235547588959 780672196 833280352 534699043 322507689696 3472000824 1 812190100 4246357772
...
Run Code Online (Sandbox Code Playgroud)
根据https://www.kernel.org/doc/Documentation/iostats.txt上的文档,
字段 4 -- 读取花费的毫秒数 这是所有读取花费的毫秒总数(从 __make_request() 到 end_that_request_last() 测量)。
字段 8 -- 写入花费的毫秒数 这是所有写入花费的毫秒总数(从 __make_request() 到 end_that_request_last() 测量)。
字段 10 -- 花费在 I/O 上的毫秒数 只要字段 9 不为零,该字段就会增加。
因此,我希望第十个字段是第四个和八个字段的总和,因为我希望总 IO 时间是阅读时间和写作时间的总和。但是,我从来没有注意到这种情况,而且我一直观察到第四和第八个字段的总和大于第十个(例如,在上面的行中 (780672196 + 3472000824 - 812190100 = 3440482920).我想知道是否有人可以解释为什么这些数字不同,似乎第十个字段试图捕获与第四个和第八个字段的总和不同的东西。
我没有看过源代码,但似乎差异源于两种不同的会计模式。
#4 和 #8 字段总结了完成每个请求所需的时间。这意味着并行发出的请求仍然每个都有助于使计数增长。
#10 字段只计算队列和磁盘繁忙的实际时间,因此它们将并行发出的请求计为一个请求。
让我们做一个实际的例子。在/boot分区上,我dd有一个 ~4 MB 的文件。看一下统计数据:
[root@localhost boot]# cat /proc/diskstats | grep sda1
8 1 sda1 46256 0 255703 19332 2063 0 4162 538 0 11207 19862
[root@localhost boot]# dd if=initramfs-0-rescue-7dc32e3935ba4ce1ae50a0a8170e4480.img of=/dev/null
84099+1 records in
84099+1 records out
43058701 bytes (43 MB) copied, 0.347783 s, 124 MB/s
[root@localhost boot]# cat /proc/diskstats | grep sda1
8 1 sda1 46342 0 339807 23011 2063 0 4162 538 0 11551 23540
[root@localhost boot]#
Run Code Online (Sandbox Code Playgroud)
读取文件需要 ~0.35s 或 ~350ms。然而,计数器 #4 和 #10 的反应方式非常不同:第一个增加了大约 4000,而后者只增加了大约 350。很容易看出哪个具有“正确”的值:它是字段 #10,正如我们所知道的dd整个操作花费了大约 350 毫秒,字段 #10 增加了同样的数量。
那么,为什么字段 #4 增加了这么多,它真正衡量的是什么?
首先,让我们了解在请求级别发生了什么。dd默认情况下,使用 512B 请求,但 linux 页面缓存以 4KB 的粒度工作,因此我们应该期望大约 1000 x 4KB 请求。这 1000 个请求被放在一个队列中并一个一个地发出(为简单起见,我们假设 NCQ 不存在)并分派到磁盘。由于机械磁盘非常擅长顺序读取,因此它们通常使用预读策略 - 即:它们读取的数据比所需的多。这意味着,在第一个 4K 请求完成后,所有其他后续请求将在很短的时间内得到服务。
让我们用疯狂的例子来做一些数学运算:
按字段 #4 测量的总请求时间:1000 个队列中请求 *每个4ms == 4000ms。这大致是字段 #4 增加的值......
底线:
绘制一个近似的并行性:考虑到多核 CPU。两个进程可以同时锤击 CPU,每个进程执行 60 秒。使用的总 CPU 时间为 120 秒(60 秒 * 2),但实际经过的时钟时间总共仍为 60 秒,因为两个进程同时运行。
| 归档时间: |
|
| 查看次数: |
5479 次 |
| 最近记录: |