news 2026/9/17 17:57:33

iostat磁盘IO性能排查实战:安装、指标解读与数据库卡顿诊断案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
iostat磁盘IO性能排查实战:安装、指标解读与数据库卡顿诊断案例

先讲个真实场景:半夜两点,告警群里跳出“数据库IO延迟飙高”。我登录服务器后,还没敲top之前,先把iostat -x -m 1 5跑了起来——这几乎成了我排查IO类问题的肌肉记忆。iostat是Linux系统里最基础的IO性能观测工具,它直接读取内核的/proc/diskstats统计信息,告诉你CPU有多少时间在等IO、每块磁盘每秒处理了多少请求、读写吞吐多少、请求排队到什么程度。这篇内容我会把iostat从头到尾讲透:不同Linux环境下怎么安装、默认输出怎么读、-x扩展指标逐项含义、数据库卡顿的完整排查案例,以及几个新手特别容易踩的指标误读坑。无论你是刚接手服务器运维的新人,还是想补全性能排查技能树的后端开发,按这篇文章的思路跑一遍,基本就能独立用iostat诊断磁盘问题了。

1. 安装背后的版本差异:不同Linux发行版各自怎么装

1.1 先搞清楚:iostat到底是不是一个独立软件

很多人第一反应是去网上找一个“iostat.rpm”下载安装,其实iostat并不独立发布,它属于sysstat工具集。同一套包里还有sar、mpstat、pidstat、sadf等命令,装好sysstat之后,这些命令会一起出现。

为什么先讲这个?因为我看过不少踩坑案例:有人手动下载一个老版本的iostat rpm,装的时候报依赖缺失,折腾半天;还有人误以为iostat需要启动服务才能用,实际上iostat是一条直接读取内核统计信息的命令,它依赖的是内核提供的/proc/diskstats/sys/block接口,跟有没有常驻进程无关。

安装sysstat包之后,默认会通过cron把系统性能数据周期性落到/var/log/sysstat目录,这部分数据供sar、sadf回看历史趋势使用;即使你不需要历史采集,也不影响iostat的使用。

1.2 CentOS/RHEL系与Debian/Ubuntu系,命令差在哪

主流的安装命令对比如下:

发行版系列安装命令自检命令
CentOS 7 / RHEL 7yum install -y sysstatrpm -q sysstat
CentOS 8+ / Rocky / AlmaLinuxdnf install -y sysstatrpm -q sysstat
Debian / Ubuntuapt update && apt install -y sysstatdpkg -l sysstat
SUSE / openSUSEzypper install -y sysstatrpm -q sysstat

补充几个细节。CentOS 7的yum源里sysstat版本偏老(比如10.1.5),字段比较旧,没有r_await/w_await;CentOS 8以后版本明显更新,输出字段更全。Ubuntu安装时如果/etc/default/sysstat里的ENABLED="false",默认不会启动定时采集任务,想用sar看历史数据就会失效;但iostat作为命令本身照样能跑。

还有一点容易忽略:一些精简容器镜像(尤其是Alpine)自带的是busybox版iostat,语法和sysstat版不完全一样,常见差异是-x参数支持的格式、输出字段单位有区别。如果你在K8s的Pod里直接敲iostat,先确认一下执行的是不是sysstat版,不要拿CentOS的习惯硬套。

1.3 没有外网的离线环境怎么办:源码编译与静态二进制

生产环境经常是内网隔离,yum/apt一律不通。我自己遇到过几次,处理思路有两种。

第一种是“在有网环境把安装包准备好”:找一台同样发行版、同样大版本的机器,用yumdownloader --resolve sysstat或者apt-get download sysstat把rpm/deb包以及依赖一并下载下来,拷进内网后离线安装。这里的关键坑是依赖收集:sysstat本身依赖很少,但不同发行版会有细微差异,本地rpm互相依赖时用rpm -ivh *.rpm一次性安装,避免按顺序逐个装时报依赖缺失。

第二种是源码编译安装:从sysstat官方源码仓库下载最新tar包,依次执行:

tar xf sysstat-12.7.5.tar.gz cd sysstat-12.7.5 ./configure --prefix=/usr/local/sysstat make sudo make install

装完后iostat通常位于/usr/local/sysstat/bin/iostat,要么把它加进PATH,要么直接用绝对路径。编译前确认机器有gcc和make。

我个人建议:能走发行版自带的包就走包,方便后续安全更新;源码编译适合临时环境或需要较新版本的场景,别在生产环境做成长期方案。

2. 拆开第一眼输出:CPU和Device两个区块到底在汇报什么

2.1 avg-cpu块:先看方向,再看数值

安装完成后直接敲iostat,输出长这样:

$ iostat Linux 5.15.0-91-generic (web01) 07/11/2024 _x86_64_ (16 CPU) avg-cpu: %user %nice %system %iowait %steal %idle 12.35 0.02 6.78 18.42 0.00 62.43 Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 86.30 1024.35 8192.61 5221444 40000000

第一块avg-cpu统计的是CPU的平均使用情况。%user是用户态程序占用CPU的比例,%nice是低优先级用户态进程,%system是内核态开销,%steal是虚拟化环境下被宿主机或其他虚拟机抢走的时间,%idle是CPU完全空闲的比例。

这几个字段里跟IO排查关系最密切的是%iowait:它表示CPU因为等待磁盘IO完成而空转的时间占比。看到%iowait明显升高,说明系统里有大量进程阻塞在磁盘读写上。但这里有个关键点容易被误解:%iowait高不代表磁盘就一定是瓶颈,它只说明“CPU在等IO”;如果业务应用本身CPU计算量很大,%user很高,%iowait反而可能很低。所以第一步只用来判断方向:系统存不存在IO等待,而不是直接定罪磁盘。

2.2 Device块的基础指标:tps、吞吐与累计值

设备块里每个字段对应一块磁盘或分区。tps表示每秒传输次数,也就是平均每秒有多少个IO请求被处理;kB_read/skB_wrtn/s代表每秒读写的数据量;kB_readkB_wrtn是从系统开机到现在的累计读写总量。

这个区块最直接的用途是看“磁盘在忙什么方向、忙到什么规模”。举例:某应用在做大文件顺序读,tps可能只有几十,但kB_read/s却能冲到几百MB;反之,一个高并发小事务系统,tps可能上千,读写速率却只有几十MB。这两种场景的瓶颈根源完全不同:前者是吞吐问题,后者是IOPS问题。

同时要注意,不带任何参数时,iostat输出的这一组数据是开机以来的累计平均值,不是当前瞬间值,所以刚开机时数值通常很低;这也是很多人第一次跑iostat觉得“服务器看起来一点都不忙”的原因。

2.3 容易看花眼的地方:kB_read/s与kB_read,以及默认块单位

新手最容易混淆的是kB_read/skB_read。注意/s后缀表示这是“速率”,是每秒读多少KB;不带/skB_read是历史累计总量。统计窗口内如果只看累计值突然变大,那可能是距离上次采样间隔久,不代表一瞬间的突发。

还有一个单位细节:iostat的默认单位是老式块(block),不一定是KB。老版本里你会看到Blk_read/s而不是kB_read/s,一个block在Linux里通常等于512字节或1KB,不同文件系统/设备可能不一样。为了不让自己在脑内换算,我几乎不会裸跑iostat,习惯直接加-k(KB)或-m(MB)。下面的章节会专门说参数组合,这里先记住一个结论:看到数值先确认单位,再谈判断。

3. 真正管用的用法都在参数细节里:-x扩展指标逐项看

3.1 不加-x,你还看不到磁盘真正的“脸色”

默认iostat只能回答“每秒多少请求、多少吞吐”,但要判断磁盘忙不忙、请求卡不卡,这两个信息远远不够。加-x之后才会输出一批关键扩展字段。看一个示例:

$ iostat -x -m 1 2 ... Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm await r_await w_await svctm %util sda 12.0 245.6 512.0 8192.0 0.0 45.0 0.0 15.5 3.25 0.50 3.40 1.02 26.4

多了这些字段:

  • r/sw/s:每秒实际下发给磁盘的读、写请求次数,区别于应用层发起的请求数。
  • rrqm/swrqm/s:每秒被内核合并掉的读、写请求数。内核IO调度器会把相邻扇区的多次请求合并成一次再下发给磁盘。合并率高说明IO模式偏连续,合并率低且r/s高说明随机小IO很多。
  • awaitr_awaitw_await:读和写请求从进入IO队列到完成处理的平均时间,单位毫秒。这是判断“卡不卡”的最直接指标。
  • avgqu-sz:设备队列的平均请求数,反映堆积程度。
  • svctm:平均服务时间,这个以后看到直接忽略,原因放在第五章。
  • %util:设备繁忙时间占采样周期的比例。

有了这些字段,才算拿到一张能诊断问题的“磁盘心电图”。

3.2 await高到底是谁的锅:队列堆积还是服务变慢

await是排查时最常看的延迟指标,但它本身是“排队时间+服务时间”的总和。同样是await很高的场景,成因可能完全不同。

现象组合推断方向
avgqu-sz高、%util接近100%、await高队列严重堆积,磁盘接近饱和,瓶颈在处理能力
avgqu-sz不高、%util不高、await偏高未发现明显排队,可能是个别IO服务时间异常,比如机械盘寻道慢或SSD写放大
%util很高、await却不高设备在处理但队列没堆起来,吞吐接近上限,延迟尚可
%util不高、r/s或w/s高、吞吐低大量碎片化小IO,更多是业务模式问题

这里涉及一个线性度问题:如果磁盘真的忙不过来,请求会在队列里排队,avgqu-sz会跟着涨,await自然变高;反过来,如果只是偶尔一次慢请求(比如机械盘磁头需要重新寻道),avgqu-sz可能并不高。把await和avgqu-sz%util放在一起看,才能准确区分是“排队排太久”还是“处理本身变慢”。

我自己的习惯是,看到await异常后,先回看avgqu-sz,再回看r/sw/s与吞吐量,四个数互相印证,基本能锁定是哪一类问题。

3.3 我常用的采样组合:iostat 1 5、-m、-y、-p、-t

命令格式是iostat [参数] [间隔秒数] [采样次数],常用组合如下:

  • iostat -x -m 1 5:每隔1秒输出一组,共5组,MB为单位。排查实时IO问题的首选。
  • iostat -x -m 1:不带次数,持续输出直到Ctrl+C。适合观察波动过程,比如做压测或业务变更时盯着看。
  • iostat -d -m -p ALL 1 2:只看设备部分,并且列出每个分区/磁盘的明细,适合确认是哪块盘、哪个分区在忙。
  • iostat -t:输出带上时间戳,后续整理汇报、回核对时间点非常有用。
  • iostat -y:跳过第一行“开机以来平均值”的报告,直接看周期内的采样,省得自己忽略第一组。
  • iostat -z:采样周期内读写的所有设备都为零时不输出该设备,磁盘数量多的时候版面干净很多。
  • iostat -N:显示LVM逻辑卷名而不是底层的/dev/mapper路径,用LVM时会友好很多。

再分享一个采样习惯:间隔建议用1秒,样本至少连续5组。IO是典型的高波动指标,某一次GC触发的刷盘可能只影响其中一两组采样;如果5组里有4组的await、%util都超了,那才是持续性问题。单次采样看到的高值,很有可能是偶发抖动,不要急着下结论。采样过程中如果加了-m,吞吐数值是MB,队列相关字段不受影响,仍然按“个”计数,不存在单位换算问题。

4. 实战案例:一次数据库服务器IO卡顿的排查全程

4.1 现象与第一轮采集:从top跳到iostat

某次业务侧反馈MySQL实例变慢,所有写操作的耗时从几毫秒涨到几百毫秒。登录服务器,先用top看整体负载:%us不算高,%wa却到了45%左右,说明确实存在明显的IO等待。紧接着我跑了iostat -x -m 1 5,核心输出如下:

avg-cpu: %user %nice %system %iowait %steal %idle 8.20 0.00 8.10 38.40 0.00 45.30 Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s await r_await w_await %util sda 35.0 620.0 512.0 8192.0 0.0 160.0 78.8 1.2 82.4 62.0

这组数据里信息量已经很大。写方向w/s高达620,写吞吐约8MB/s,w_await高达82.4ms,而r_await只有1.2ms;队列字段avgqu-sz大概在0.5左右(示例中未完全列出,采集时可以额外关注)。

4.2 判读思路:方向、规模、时延、趋势四个维度

拿到数据之后我的判断路径是固定的四步:

第一步看方向。w/s620、wkB/s约8MB/s,读方向r/s只有35,问题焦点明显在写。

第二步看规模。620次每秒的写请求不算夸张,8MB/s的吞吐也很小,说明不是大流量把带宽打满,而是小IO特别多,大概率是大量小事务在频繁提交。

第三步看时延分量。w_await82ms对比r_await1.2ms,写延迟拉高;同时avgqu-sz只有0.5,队列里并没有堆积多少请求。这两个信息合在一起,意味着瓶颈不是“请求排长队”,而是“每次写请求本身处理得很慢”。如果avgqu-sz很高、%util接近100%,那我会判断磁盘处理能力到极限;这里avgqu-sz不高,方向就得往“写路径上的机制问题”去想。

第四步看趋势。连续5次采样要全部看过,确认w_await%util不是只爆了一组,五次都维持在相近水平,排除偶发抖动。

四步走完,可以初步排除“磁盘带宽打满”和“整盘硬件故障”这两类可能,重点怀疑小写刷盘路径。

4.3 顺着iotop找到元凶,以及后续的确认步骤

iostat只能定位到“哪块设备在忙、忙在什么方向”,但哪个进程造成的,需要配合iotop。我在同一条命令里执行iotop -d 1 -o,只显示有IO活动的进程,结果几乎清一色是mysqld,大量线程处于D状态(不可中断睡眠)。

再进MySQL看一眼Innodb_log_waits状态,数值持续增长,说明redo log写入等待确实在累积。到这里,整个链路就串起来了:应用侧大量小事务并发提交,每个事务都要写redo log并触发fsync刷盘,写请求又碎又密,把磁盘写路径拖慢了;磁盘本身的绝对能力没到极限,但小IO模式导致每次fsync都要付出较长的处理时间。

后续的调整分两步。MySQL侧,把innodb_flush_log_at_trx_commit从1改为2,让事务提交不必每次都强制刷盘,同时结合group commit进一步合并刷盘;应用侧,把高频的单条update改造成批量提交,明显减少提交次数。改完再跑一轮iostat -x -m 1 5w/s降到120左右,w_await回落到10ms以内,业务侧延迟恢复正常。

这里必须加一句提醒:innodb_flush_log_at_trx_commit改为2,会对崩溃安全度有影响,改之前务必和业务方确认持久性要求。我讲这个案例的重点是演示如何用iostat数据一步步缩小排查范围,而不是让你照抄这个参数值。

5. 容易被误读的指标与踩坑记录

5.1 %util到100%,磁盘真的废了吗

%util的计算方式是统计采样周期内“设备有请求在处理”的时间占比,它表达的是“设备忙不忙”,不是“设备每秒能处理多少请求的利用率”。对于传统机械硬盘,单个盘同一时刻基本只能处理一个请求,%util接近100%确实意味着接近物理上限。

但SSD、尤其是NVMe盘,内部是多通道并发架构,支持多队列多命令并行处理,设备可能同时服务十几个请求,%util显示100%但离真实上限还远。我见过不少线上服务器,%util长期100%,业务却毫无卡顿,tps和吞吐还能继续往上走。

所以现在看%util,我只会把它当成“繁忙度”参考,不单独用它判断是否到极限;真正的瓶颈判断还得结合await和avgqu-sz:util高但await低,说明处理得过来;util高且await涨,说明开始排队了;util不高但await也涨,大概率是慢IO或硬件问题。

5.2 容器环境里看到的不一定是容器自己的负载

iostat依赖/proc/diskstats,这个文件记录的是宿主机的全局磁盘统计,不是某个容器的cgroup IO统计。你在容器里执行iostat,看到的磁盘设备和负载,基本都是宿主机的视角。

也就是说,如果宿主机上另一个容器在疯狂写日志,你在自己容器里跑iostat,可能会看到很高的%util和吞吐,但这根本不是你的容器产生的负载。反过来,如果你的容器被限制了IO,iostat也同样显示不出你的限额使用情况。

要做容器维度的IO监控,需要看cgroup的blkio接口(比如/sys/fs/cgroup/blkio/下的统计文件),或者用专门的容器监控组件。这个坑在K8s环境里特别常见,新手排查容器性能问题时容易被误导,我建议尽量在宿主机层面对照着看,别把容器里的iostat输出当成容器的真实IO画像。

5.3 老版本的svctm,以及字段差异引发的误读

svctm这个字段,在man手册里早就被标注为不建议使用。因为内核压根不统计“单次IO平均服务时间”,它只是用%util和tps之间的关系间接推算出来的,在队列非空、突发IO场景下完全失真。所以无论老手新手,看到svctm那一列直接跳过即可。

另外,不同版本的sysstat输出字段差异也容易让人懵:较老的版本没有r_await/w_await,只有合并的await;老版本默认显示Blk_read/s而不是kB_read/s;还有的发行版默认单位是block,数值看起来会大一截。

如果你拿网上教程的字段对照本地输出,发现对不上,先跑iostat -V看版本,再对照手册,别直接怀疑是命令装错了。我自己在跨发行版排查时就栽过这个跟头,同一台机器不同环境装出来的sysstat版本不同,输出列的排序和字段数量都可能有差异,养成看版本的习惯能省很多事。

最后再分享一个排查习惯。我每次处理IO问题,都会顺手把三组数据记进本地的备忘:基线值(业务正常时iostat关键字段)、异常值(告警时差了多少)、恢复值(调整后回到了什么水平)。没有基线的iostat解读,基本等于盲猜。另外,我建议把iostat、vmstat、iotop、sar四个工具放一起配合用:iostat看设备层状态、vmstat看系统全局(包括swap和内存回收)、iotop定位进程级IO来源、sar回看历史趋势。四个工具互相验证,比单独抱着iostat一个输出琢磨半天要靠谱得多。希望这篇文章能让你在下次遇到IO问题时,不用再对着iostat的输出发愣。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 17:57:24

ThinkPHP8整合Workerman实现高性能WebSocket服务

1. 项目概述最近在重构一个需要实时通信功能的项目时,我选择了ThinkPHP8作为基础框架,同时整合Workerman来实现高性能的WebSocket服务。这种组合在实际项目中非常实用,既能利用ThinkPHP成熟的MVC架构,又能通过Workerman突破传统PH…

作者头像 李华
网站建设 2026/9/17 17:57:23

SQL Server日期时间格式转换:CONVERT样式代码详解与性能优化

做SQL Server开发的人,迟早会遇到这样的需求:把一个datetime字段输出成2024-01-15这种纯日期,或者拼成20240115作为流水号,又或者要把"2024年1月15日"这样的中文格式塞进报表里。很多人第一反应是拿字符串函数去截取&am…

作者头像 李华
网站建设 2026/9/17 17:56:02

达梦数据库透明加密:库表列三级配置与密钥管理

"达梦数据库透明加密"这个能力,最早让我真正重视起来是几年前一个客户的验收环节。对方提的要求很朴素:数据库里的身份证号、手机号,在磁盘上不允许是明文。我当时的方案是应用层加密,字段落库前用代码加密,…

作者头像 李华
网站建设 2026/9/17 17:53:52

Spring Boot体育场馆预约系统开发实战

1. 项目背景与核心价值体育场馆预约系统是当前校园和社区体育设施管理的重要工具。传统的人工预约方式存在诸多痛点:电话预约容易占线、现场排队耗时费力、纸质登记易出错且难以统计。基于Spring Boot的解决方案能够有效解决这些问题,实现24小时在线预约…

作者头像 李华
网站建设 2026/9/17 17:51:03

文华财经指标公式实战:麦语言拆解、参数化过滤与跨平台迁移

简介:这份资源是一份文华财经(文华公式)指标公式文档,面向使用文华财经软件进行期货行情分析、希望借助成熟指标判断趋势与关键转折的交易者与公式编写爱好者。文档由一位被称为顶尖期货高手的使用者整理,核心围绕局部…

作者头像 李华