FROM: iostat来对linux硬盘IO性能进行了解
iostat 是sysstat 一组件, 用来即时显示系统, 比如 自从系统启动开始的 CPU 平均时间 (与 uptime相似) 和整个系统, 适配器, tty 设备, 磁盘 etc 的输入/输出统计信息.
iostat [ -c ] [ -d ] [ -N ] [ -n ] [ -h ] [ -k | -m ] [ -t ] [ -V ] [ -x ] [ -z ] [ device [...] | ALL ] [ -p [ device [,...] | ALL ] ] [interval [ count ] ]
OPTION
-c 显示 CPU 使用的相关信息
-d 显示磁盘使用的相关信息
-h 加-n参数时, 以易读的方式显示 NFS 的相关信息
-k 以 KB/s 为单位代替 blocks/s 显示统计信息. NOTE: kernel >= v2.4, 数据才能正确显示
-m 以 MB/s 为单位代替 blocks/s or KB/s 显示统计信息. NOTE: kernel >= v2.4, 数据才能正确显示
-N 显示映射的设备信息, 用于查看 LVM2 的统计信息
-n 显示 NFS 的统计信息NOTE: kernel >= v2.6.17
-p [ { device [,...] | ALL } ] 显示系统所用到的块设备 or 指定的设备及其分区的统计信息. NOTE: kernel = v2.5
-t 输出的每一行边上的时间戳记. 时间戳格式由环境变量 S_TIME_FORMAT所决定
-V 显示版本信息
-x 显示扩展信息. NOTE: 因为其需要 /proc/diskstats 文件 or 挂载 sysfs, 所以 kernel = v2.5. 但如果 kernel 有 patch /proc/partitions, 老版本 kernel(e.g. 2.4) 也可以选用该参数
-z 测试时段时, 如果设备的输出不处于 activity 状态, 则将其忽略
interval 参数指定在每个报告之间的以秒计算的时间量. 第一份报告包含了自系统启动 (引导) 以来的时间统计信息. 每一份后继报告都包含在和前一份报告的时间间隔之间收集的统计信息
count 参数可被指定来连接 interval 参数. 如果指定了 count 参数, 它的记数值就确定在 interval 秒间生成的报告数. 如果指定了 interval 参数但没有 count 参数, iostat 命令就会不断生成报告
输出解析
对于kernel 2.4, iostat 的数据的主要来源是 /proc/partitions, 而对于kernel 2.6, 数据主要来自 /proc/diskstats 或 /sys/block/[block-device-name]/stat.
/proc/partitions 信息
[root@localhost ~]# cat /proc/partitions
major minor #blocks name
3 0 11534336 hda
3 1 522081 hda1
3 2 2096482 hda2
3 3 8908042 hda3
- major 主设备号, 3 代表 hda
- minor 次设备号, 1 代表 No.1 分区
- #blocks 设备总块数 (1024 bytes/block), 11 534 336 * 1024 = 11 811 160 064(bytes) ~ 1G
- name 设备名称, e.g. hda1
iostat 输出结果
[root@localhost ~]# iostat
Linux 2.6.18-92.el5 (localhost.localdomain) 03/17/2011 _i686_ (1 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.03 0.03 0.13 0.03 0.00 99.78
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
hda 0.88 0.25 10.86 2282383 100713668
CPU 使用情况
CPU 值是所有处理器的总平均, 同时, I/O 等待状态是系统级定义的, 而不是每个处理器.
- %user 显示用户级别(应用) 所占用 CPU 的百分比
- %nice 显示拥有 nice 优先级用户所占用 CPU 的百分比
- %system 显示系统级别(内核) 所占用 CPU 的百分比
- %iowait 显示等待 IO 所占用 CPU 的百分比
- %steal
- %idle 显示空闲 CPU 的百分比
磁盘使用情况
- tps 设备每秒钟传输的数量(每秒钟 I/O 的请求数). 多个单独的 I/O 请求看合并到一个传输请求中, 因为每个传输请求可以有不同的大小
- Blk_read/s Blk_wrtn/s 每秒钟块设备读写块的数量. 可设置不同的块大小, 一般为1024, 2048, 4048字节, 取决于分区的容量.
- Blk_read Blk_wrtn 显示自系统启动后读写块的总数
对于配置有大量磁盘的大型系统配置, 当 iostat 没有执行时, 系统可以设置为避免收集物理硬盘的 I/O 数据. 如果系统用上述的方式配置, 那么第一个磁盘报告将显示消息引导不可用后 的磁盘历史记录而不是磁盘统计信息. 由 iostat 命令生成的后继时间间隔报告包含在报告时间间隔期间收集的磁盘统计信息. 引导后的任何 tty 和 CPU 都不会影响. 如果一个系统管理命令用来重新保留磁盘统计信息, 那么第一个 iostat 命令报告会显示从启用磁盘输入/输出统计信息那一刻时间间隔起点起的行为.
注: 可使用如下命令来获得 /dev/hda1 的块大小
[root@localhost ~]# dumpe2fs -h /dev/hda1 | grep -F "Block size"
dumpe2fs 1.39 (29-May-2006)
Block size: 1024
iostat -x 输出结果
[root@localhost ~]# iostat -x
Linux 2.6.18-92.el5 (localhost.localdomain) 03/17/2011 _i686_ (1 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.03 0.03 0.13 0.03 0.00 99.78
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
hda 0.00 0.49 0.01 0.87 0.25 10.86 12.62 0.00 4.51 0.91 0.08
- rrqm/s 每秒进行 merge 的读操作数目, 即 delta(rmerge)/s
- wrqm/s 每秒进行 merge 的写操作数目, 即 delta(wmerge)/s
- r/s 每秒完成的读 I/O 设备次数, 即 delta(rio)/s
- w/s 每秒完成的写 I/O 设备次数, 即 delta(wio)/s
- rsec/s 每秒读扇区数, 即 delta(rsect)/s
- wsec/s 每秒写扇区数, 即 delta(wsect)/s
- rkB/s 每秒读 K 字节数, 是 rsect/s 的一半, 因为每扇区大小为 512 字节
- wkB/s 每秒写 K 字节数, 是 wsect/s 的一半
- avgrq-sz 平均每次设备 I/O 操作的数据大小 (扇区), 即 delta(rsect+wsect)/delta(rio+wio)
- avgqu-sz 平均 I/O 队列长度, 即 delta(aveq)/s/1000 (因为aveq的单位为毫秒)
- await 平均每次设备 I/O 操作的等待时间 (毫秒), 即 delta(ruse+wuse)/delta(rio+wio)
- svctm 平均每次设备 I/O 操作的服务时间 (毫秒), 即 delta(use)/delta(rio+wio)
- %util 一秒中有百分之多少的时间用于 I/O 操作, 或者说一秒中有多少时间 I/O 队列是非空的, 即 delta(use)/s/1000 (因为use的单位为毫秒)
I/O 系统 VS 超市排队
举一个例子, 我们在超市排队 checkout 时, 怎么决定该去哪个交款台呢? 首当是看排的队人数, 5个人总比20人要快吧? 除了数人头, 我们也常常看看前面人购买的东西多少, 如果前面有个采购了一星期食品的大妈, 那么可以考虑换个队排了. 还有就是收银员的速度了, 如果碰上了连钱都点不清楚的新手, 那就有的等了. 另外, 时机也很重要, 可能 5 分钟前还人满为患的收款台, 现在已是人去楼空, 这时候交款可是很爽啊, 当然, 前提是那过去的 5 分钟里所做的事情比排队要有意义 (不过我还没发现什么事情比排队还无聊的).
I/O 系统也和超市排队有很多类似之处:
- r/s+w/s 类似于交款人的总数
- 平均队列长度(avgqu-sz)类似于单位时间里平均排队人的个数
- 平均服务时间(svctm)类似于收银员的收款速度
- 平均等待时间(await)类似于平均每人的等待时间
- 平均I/O数据(avgrq-sz)类似于平均每人所买的东西多少
- I/O 操作率 (%util)类似于收款台前有人排队的时间比例
我们可以根据这些数据分析出 I/O 请求的模式, 以及 I/O 的速度和响应时间.
实例
# iostat -x 1
avg-cpu: %user %nice %sys %idle
16.24 0.00 4.31 79.44
rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util
/dev/cciss/c0d0
0.00 44.90 1.02 27.55 8.16 579.59 4.08 289.80 20.57 22.35 78.21 5.00 14.29
.......
上面的 iostat 输出表明秒有 28.57 次设备 I/O 操作: delta(io)/s = r/s + w/s = 1.02 + 27.55 = 28.57 (次/秒) 其中写操作占了主体 (w:r = 27:1).
平均每次设备 I/O 操作只需要 0.91 就可以完成, 但每个 I/O 请求却需要等上 78 ms, 为什么? 因为发出的 I/O 请求太多 (每秒钟约 29 个), 假设这些请求是同时发出的, 那么平均等待时间可以这样计算:
平均等待时间 = 单个 I/O 服务时间 * ( 1 + 2 + … + 请求总数-1) / 请求总数
应用到上面的例子: 平均等待时间 = 5ms * (1+2+…+28)/29 = 70ms, 和 iostat 给出的 78ms 的平均等待时间很接近. 这反过来表明 I/O 是同时发起的.
每秒发出的 I/O 请求很多 (约 29 个), 平均队列却不长 (只有 2 个 左右), 这表明这 29 个请求的到来并不均匀, 大部分时间 I/O 是空闲的.
一秒中有 14.29% 的时间 I/O 队列中是有请求的, 也就是说, 85.71% 的时间里 I/O 系统无事可做, 所有 29 个 I/O 请求都在142毫秒之内处理掉了.
delta(ruse+wuse)/delta(io) = await = 78.21 => delta(ruse+wuse)/s = 78.21 * delta(io)/s = 78.21*28.57 = 2232.8, 表明每秒内的I/O请求总共需要等待2232.8ms. 所以平均队列长度应为 2232.8ms/1000ms = 2.23, 而 iostat 给出的平均队列长度 (avgqu-sz) 却为 22.35(sysstat >= v4.1.6 已修改该问题 )
准则
- 如果 %util 接近 100%, 说明产生的I/O请求太多, I/O系统已经满负荷, 该磁盘可能存在瓶颈.
- svctm 一般要小于 await (因为同时等待的请求的等待时间被重复计算了), svctm 的大小一般和磁盘性能有关, CPU/内存的负荷也会对其有影响, 请求过多也会间接导致 svctm 的增加. await 的大小一般取决于服务时间(svctm) 以及 I/O 队列的长度和 I/O 请求的发出模式. 如果 svctm 比较接近 await, 说明 I/O 几乎没有等待时间;如果 await 远大于 svctm, 说明 I/O 队列太长, 应用得到的响应时间变慢, 如果响应时间超过了用户可以容许的范围, 这时可以考虑更换更快的磁盘, 调整内核 elevator 算法, 优化应用, 或者升级 CPU.
- 队列长度(avgqu-sz)也可作为衡量系统 I/O 负荷的指标, 但由于 avgqu-sz 是按照单位时间的平均值, 所以不能反映瞬间的 I/O
Tagged iostat, Linux