iostat的深入理解
问题背景
iostat -xdm 1 通常用来查看机器磁盘IO的性能。
我们一般会有个经验值,比如,ioutil要小于80%, svctm要小于2ms。
前几天碰到一个奇怪的现象:有一台SSD机器,磁盘的iops在1万多,吞吐量在100多M,看来压力并不大,但是ioutil一直在90%以上。SSD的磁盘怎么会只能承受这么点压力?
下面是当时tsar的数据:
针对这个问题的结论
- ioutil是繁忙度的一个度量(非空闲时间)。对于后面有多块磁盘支撑的虚拟设备意义不大。所以对于SSD,并不能说ioutil到了100%了,磁盘就到达最大极限性能了。
官方文档的描述
Percentage of elapsed time during which I/O requests were issued to the device (bandwidth utilization for the device).
Device saturation occurs when this value is close to 100% for devices serving requests serially.
But for devices serving requests in parallel, such as RAID arrays and modern SSDs,
this number does not reflect their performance limits.
-
await是平均IO响应时间,包括在驱动请求队列里的等待和设备的IO响应时间(ms)。
-
svctm是一个推断值。计算方法: svctm = ioutil/IOPS = ioutil/(rs+ws)
比如,在1s内,60%的使用率,有300的IOPS,那么平均服务时间svctm = 600ms/300 = 2ms
在未来某个版本的iostat会被删除,官方文档是这样描述原因的。
官方文档的描述
The average service time (svctm field) value is meaningless,
as I/O statistics are calculated at block level,
and we don’t know when the disk driver starts to process a request.
For this reason, this field will be removed in a future sysstat version.
Linux内核IO协议栈结构
Linux整体IO体系可以分为七层,它们分别是:
-
VFS层:虚拟文件系统层。由于内核要跟多种文件系统打交道,而每一种文件系统所实现的数据结构和相关方法都可能不尽相同,所以,内核抽象了这一层,专门用来适配各种文件系统,并对外提供统一操作接口。
-
文件系统层:不同的文件系统实现自己的操作过程,提供自己特有的特征。
-
页缓存层:负责针对page的缓存。
-
通用块层:由于绝大多数情况的io操作是跟块设备打交道,所以Linux在此提供了一个类似vfs层的块设备操作抽象层。下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准。
-
IO调度层:因为绝大多数的块设备都是类似磁盘这样的设备,所以有必要根据这类设备的特点以及应用的不同特点来设置一些不同的调度算法和队列。以便在不同的应用环境下有针对性的提高磁盘的读写效率,这里就是大名鼎鼎的Linux电梯所起作用的地方。针对机械硬盘的各种调度方法就是在这实现的。
-
块设备驱动层:驱动层对外提供相对比较高级的设备操作接口,往往是C语言的,而下层对接设备本身的操作方法和规范。
-
块设备层:这层就是具体的物理设备了,定义了各种真对设备操作方法和规范。
简图
还有一张更详细的图,图上已有出处:
iostat是怎么计算的?
- /proc/diskstats 内核进行了多少IO,IO的耗时统计,都是会记录在/proc/diskstats。
$cat /proc/diskstats | grep -w sdb
8 16 sdb 5599308471 607 262844839314 1688433460 18293450260 0 402591421472 167371198 4 3337033295 1847117638
格式:
前3列定位一个设备。这个文件是每毫秒更新一次。
- /sys/block/${device_name}/stat
这个文件记录的内容实际上和/proc/diskstats 完全一样的,只不过,这个文件只针对某个设备,或是分区,因此,只有一行内容,也比/proc/diskstats 少前3列,不用单独定位一个设备。
$cat /sys/block/sdb/stat
5599363483 607 262845774770 1688449447 18294010908 0 402598669112 167535796 0 3337131224 1847298025
f1: read_IOs, 读次数
f2: read_merges, 合并读次数。比如,两个地址连续的IO,真正下发到设备,会合并成一个IO
f3: read_sectors, 读扇区的次数
f4: read_ticks, 读花费的毫秒数
f5: write_IOs, 写次数
f6: write_merges, 合并写次数
f7: write_sectors, 写扇区次数
f8: write_ticks, 写操作花费的毫秒数
f9: in_flight, 正在处理的IO请求数,The number of I/Os currently in flight. It does not include I/O requests that are in the queue but not yet issued to the device driver.
f10: io_ticks, IO操作花费的毫秒数,每次队列中有IO,就增加。This value counts the time during which the device has had I/O requests queued.
f11: time_in_queue, The number of I/Os in progress (field 9) times the number of milliseconds spent doing I/O since the last update of this field.