Linux IO磁盘篇整理小记

作者:朱小厮来源:https://www.jianshu.com/p/76ca793daf1d一、概述
本篇起源于对Kafka的一个问题排查,大致的原因是达到磁盘性能瓶颈 。在追踪问题的时候用到IOStat -x这命令,详细示例如下:

Linux IO磁盘篇整理小记

文章插图
 
 
可以看到%idle(%idle小于70%说明IO压力已经比较大了)和%util的值都处于非正常状态 。不过这里并不讲述Kafka的问题排查过程,反而是来讲述下IO指标的一些知识 。每次遇到需要查看磁盘相关信息的时候,一些指标都会或多或少的遗忘,还要翻阅各种资料了解,故这里对相关的信息做一个相关的整理,在巩固相关知识点的同时也方便以后的查阅 。
上面示例中的各个指标的含义分别为:
avg-cpu说明:
%user:在用户级别运行所使用的CPU的百分比 。
%nice:带nice值(和进程优先级相关)的用户模式下运行所使用的CPU的百分比 。
%system:在系统级别运行所使用CPU的百分比 。
%iowait:CPU等待IO完成的时间百分比 。(单个iowait指标值偏高并不能说明磁盘存在IO瓶颈,下面会有详述 。)
%steal:管理程序维护另一个虚拟处理器时,虚拟CPU的无意识等待时间的百分比 。
%idle:CPU空闲时间的百分比 。(idle值高,表示CPU较空闲 。)
device说明:
rrqm/s:每秒进行merge的读操作数目 。即:rmerge/s
wrqm/s:每秒进行merge的写操作数目 。即:wmerge/s
r/s:每秒完成的读IO设备的次数 。即rio/s
w/s:每秒完成的写IO设备的次数 。即wio/s
rsec/s:每秒读扇区数 。即rsect/s(每个扇区大小为512B 。)
wsec/s:每秒写扇区数 。即wsect/s
avgrq-sz:平均每次设备IO操作的数据大小(扇区);平均单次IO大小 。
avgqu-sz:平均IO队列长度 。
await:从请求磁盘操作到系统完成处理,每次请求的平均消耗时间,包括请求队列等待时间;平均IO响应时间(毫秒) 。
svctm:平均每次设备IO操作的服务时间(毫秒) 。
%util:一秒中有百分之多少的时间用于 I/O 操作,即被io消耗的cpu百分比 。
正常情况下svctm应该是小于await值的,而svctm的大小和磁盘性能有关,CPU、内存的负荷也会对svctm值造成影响,过多的请求也会间接的导致svctm值的增加 。await值的大小一般取决于svctm的值和IO队列的长度以及IO请求模式,如果scvtm比较接近await,说明IO几乎没有等待时间;如果await远大于svctm,说明IO请求队列太长,IO响应太慢,则需要进行必要优化 。(可以看完下面一节再来回顾这段内容 。)
如果%util接近100%,说明产生的IO请求太多,IO系统已经满负荷,该磁盘可能存在瓶颈 。
队列长度(avgqu-sz)也可作为衡量系统 I/O 负荷的指标,但由于 avgqu-sz 是按照单位时间的平均值,所以不能反映瞬间的 I/O 泛洪,如果avgqu-sz比较大,则说明有大量IO在等待 。
二、相关原理
对于await, svctm以及%util等,光从概念上来说,比较晦涩,可以通过下图的磁盘IO流程来加深理解:
Linux IO磁盘篇整理小记

文章插图
 
 
(此图来源于遗产流....重新画了一遍)
磁盘IO场景
1. 用户调用标准C库进行IO操作,数据流为:应用程序buffer->C库标准IObuffer->文件系统page cache->通过具体文件系统到磁盘 。
2. 用户调用文件IO,数据流为:应用程序buffer->文件系统page cache->通过具体文件系统到磁盘 。
3. 用户打开文件时使用O_DIRECT,绕过page cache直接读写磁盘 。
4. 用户使用类似dd工具,并使用direct参数,绕过系统cache与文件系统直接写磁盘 。
发起IO请求请的步骤简析(以最长链路为例)
写操作:
1. 用户调用fwrite把数据写C库标准IObuffer后就返回,即写操作通常是个异步操作 。
2. 数据到C库标准IObuffer后,不会立即刷新到磁盘,会将多次小数据量相邻写操作先缓存起来合并,最终调用write函数一次性写入(或者将大块数据分解多次write调用)page cache 。
3. 数据到page cache后也不会立即刷新到磁盘,内核有pdflush线程在不停的检测脏页,判断是否要写回到磁盘中,如果是则发起磁盘IO请求 。
读操作:
1. 用户调用fread到C库标准IObuffer读取数据,如果成功则返回,否则继续 。
2. 到page cache读取数据,如果成功则返回,否则继续 。
3. 发起IO请求,读取到数据后缓存buffer和C库标准IObuffer并返回 。可以看出,读操作是同步请求 。


推荐阅读