小心dstat的磁盘统计BUG

最近用 dstat 看系统 IO,发现磁盘读取远高于预期,在代码里摸爬了好久,实在找不出代码有什么问题;

为了排除了系统 cache 预取的可能,先禁用 cache 预取 (详见此文

echo 0 > /sys/block/sda/queue/read_ahead_kb

还找了个测试脚本(详见此贴):

FILENAME=/tmp/test.tmp
BLOCKSIZE=1M
BLOCKCOUNT=100

echo ‘— Write —‘
dd if=/dev/zero of=$FILENAME bs=$BLOCKSIZE count=$BLOCKCOUNT conv=fsync

echo 3 > /proc/sys/vm/drop_caches
echo 0 > /proc/sys/vm/drop_caches

echo ‘—Read —‘
dd if=$FILENAME of=/dev/zero bs=$BLOCKSIZE count=$BLOCKCOUNT

rm -f $FILENAME

测试结果发现同样会有问题,看来自己的程序问题和系统 cache 原因都被排除了,
在绝望中换用 iostat 和 vmstat 观察,发现结果和 dstat 不同。

经过一番研究,终于发现,原来是 dstat 的 BUG,导致统计值翻倍,此 BUG 在 0.7.0 以后版本中已得到修复,而我用的是在 CentOS5 中用 yum 装的 0.6.6 版。

the problem likely is that /proc/diskstats in newer kernels also
provide proper stats for partitions, which it doesn’t do on older kernels:

[dag@rhun ~]$ cat /proc/diskstats | grep sda
8 0 sda 196482 22091 3600800 1524365 304150 614172 7355412 45110870 0 1321463 46646670
8 1 sda1 1033 10862 2 4
8 2 sda2 215888 3587367 919426 7355408
8 3 sda3 1199 1411 0 0
8 4 sda4 427 872 0 0

另外 iostat 和 vmstat 也让很人郁闷,这两个工具默认显示的是 block 数而非 IO 的字节数,而且两个工具所使用的 block size 并不一致。

iostat 默认的 block size是 512 bytes,详见man page;使用 iostat 可以加 -k 或 -m 直接显示字节数。

Blk_read/s
Indicate the amount of data read from the device expressed in a number of blocks per second. Blocks are equivalent to sectors  with  2.4  kernels  and
newer and therefore have a size of 512 bytes. With older kernels, a block is of indeterminate size.

vmstat 默认的 block size 是 1024 bytes, 详见此文