
iostat这个命令我在日常运维里用的频率非常高。不管你是刚接手服务器的新人还是处理过多次性能故障的老手只要和 Linux 服务器打交道磁盘 I/O 就是绕不开的一环。而 iostat 恰恰是查看磁盘读写状态最直接的工具之一。尤其是当应用响应变慢、数据库压测上不去、文件服务卡顿的时候我第一反应往往不是去看 CPU 或内存而是先跑几条 iostat 命令快速确认磁盘是不是瓶颈。这篇内容我把 iostat 的安装、输出字段、常见误区、实战排查思路和监控技巧一次讲清楚尽量用我平时实际操作中的“人话”来描述帮你少踩点坑。iostat 属于 sysstat 软件包它的核心功能是监控系统输入输出设备主要是磁盘的负载情况。它能告诉你磁盘当前每秒读写了多少数据、每秒处理了多少次 I/O 请求、平均每次请求耗时多久、设备使用率达到了多少。这些数据合在一起基本就能判断出一块磁盘是“在正常工作”还是“已经满负荷运转”。这篇文章适合所有需要维护 Linux 服务器的人也适合刚学习系统监控的同学参考。我会结合自己排查过的真实场景把安装方法、字段含义、常见坑和高级用法都展开说一下。1. 先搞清楚 iostat 能做什么再看怎么装1.1 一个真实的排查场景大概半年前我们有一套线上应用经常在高峰期出现“卡住”的情况。登录服务器看 CPU 使用率并不高内存也充足但接口响应时间就是做不到原先的水平。当时我走了不少弯路查了应用日志、看了慢查询、检查了网络最后才想到用 iostat 看一下磁盘。结果发现一块云数据盘的%util长期在 90% 以上await也高得离谱问题立刻就明确了磁盘 I/O 已经接近饱和应用里的每一次文件读写都在排队。后来通过扩容磁盘和调整读写策略才彻底解决。这个场景其实很有代表性。CPU、内存、磁盘、网络四大件里磁盘 I/O 问题往往最隐蔽因为它不像 CPU 那样有一个明显的“高占用”指标很多时候应用的表现只是“慢”或者“偶尔卡住”。iostat 的价值就在于它能把磁盘层的真实压力量化出来让你不用靠猜。1.2 一条命令能拿到哪些关键数据iostat 从内核获取数据然后以列表形式展示。主要有两大块内容CPU 层面的统计%user、%system、%iowait、%idle等。这里重点看%iowait它代表 CPU 等待磁盘 I/O 完成的时间占比。如果这个数值持续偏高说明 CPU 闲着等磁盘磁盘大概率是短板。设备层面的统计包括tps每秒传输次数、kB_read/s、kB_wrtn/s、await平均每次 I/O 请求的处理时间、%util设备忙碌百分比等。这一块是分析磁盘性能的核心能直接看出吞吐量、响应延迟和使用率。这些指标合在一起基本能回答三个问题磁盘忙不忙有多忙请求响应快不快1.3 哪些人应该重点掌握 iostat数据库管理员DBA需要关注数据库数据文件所在磁盘的压力后端开发在排查接口延迟时需要排除磁盘因素运维工程师做服务器巡检和故障定位时iostat 基本是标准动作做性能测试的同学更需要用它观察压测过程中磁盘是否成为瓶颈。可以说只要你的应用涉及文件存储、数据库读写或日志输出iostat 就值得你花半小时掌握。2. iostat 安装不同系统对应不同方法2.1 RHEL/CentOS 系列安装在 CentOS、Rocky Linux、AlmaLinux 这类系统上iostat 属于 sysstat 包直接通过 yum/dnf 安装即可yum install -y sysstat如果你的系统是较新的 RHEL 9 或 Rocky Linux 9可能需要用 dnf 命令但包名是一样的。安装完成后可以用rpm -ql sysstat | grep iostat确认可执行文件路径。通常是在/usr/bin/iostat下。有一个需要注意的点yum install sysstat会同时安装sar、pidstat、mpstat等命令这是一整套 sysstat 工具。如果你只需要 iostat目前没有更轻量的独立安装方式接受整套即可。不过这也算好事后面做性能分析时sar和pidstat能派上大用场。2.2 Debian/Ubuntu 系列安装Debian、Ubuntu 系统使用 apt 安装apt update apt install -y sysstatUbuntu 上安装 sysstat 后有个细节默认情况下 sysstat 的定时收集服务是关闭的配置文件在/etc/default/sysstat里面有一行ENABLEDfalse。如果你后面想用sar的历史数据需要改成ENABLEDtrue再重启服务。不过 iostat 本身是即时读取内核数据的不依赖这个开关所以仅用 iostat 的话可以不改动它。2.3 源码编译安装的方法如果你的生产环境比较特殊比如是内网离线环境无法用 yum/apt 安装那就需要先下载 sysstat 源码包然后编译安装。这里分享一个我常用的离线安装思路准备 RPM 包或 DEB 包拷到目标机器上用rpm -ivh或dpkg -i安装。这种方式最简单但需要找到匹配系统版本的包。如果找不到现成包可以用源码编译。步骤大致是wget http://pagesperso-orange.fr/sebastien.godard/sysstat-12.7.4.tar.gz tar -zxvf sysstat-12.7.4.tar.gz cd sysstat-12.7.4 ./configure make make install这里要提醒一句源码编译默认安装路径通常是/usr/local/bin而不是/usr/bin。编译完成后执行which iostat查看路径如果找不到需要把路径加入 PATH或者用/usr/local/bin/iostat直接调用。另外编译过程依赖 gcc、make 等基础工具离线环境最好提前确认这些工具已存在。2.4 验证是否安装成功安装完成后执行iostat -V或iostat -v查看版本号能打印版本就说明安装成功。第一次执行iostat时你可能会发现显示的数值看起来很大或者某些字段跟网上教程不一样这些都是正常现象。因为 iostat 第一次执行显示的是从系统开机到现在的平均数据而不是“当前瞬间”的数据。想要看实时的、准确的负载情况必须带时间间隔参数比如iostat -x 1 3。这是很多新手容易踩的第一个坑。3. 输出字段逐个拆解看懂 iostat 怎么“说话”3.1 最基础的执行方式直接执行iostat系统会打印从开机到当前的平均统计信息。如下是一个典型输出avg-cpu: %user %nice %system %iowait %steal %idle 2.55 0.00 0.85 0.23 0.00 96.37 Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn vda 8.12 251.36 98.75 10847332 4261378这里Device是设备名称tps是每秒 I/O 传输次数kB_read/s和kB_wrtn/s是每秒读写数据量kB_read和kB_wrtn是从开机到现在的累计读写量。此输出相当于一个“总账”排查问题时价值不大因为它是所有时刻的平均值会把峰值掩盖掉。3.2 我常用的几个参数组合排查问题我一般不会只跑裸 iostat而是带上参数组合最常用的几组如下iostat -x 1 3这个命令的意思是每 1 秒刷新一次连续输出 3 次同时使用-x参数显示扩展统计信息。-x参数会额外显示rrqm/s、wrqm/s、r_await、w_await、aqu-sz、%util等字段这些才是定位磁盘性能问题的关键信息。iostat -d 1 5只显示设备使用状态不显示 CPU 状态。适合脚本里定期抓取设备负载。iostat -k -x 2 2-k表示以 KB 为单位显示读写速度。默认 iostat 输出的单位是 KB但在某些新版本里默认可能是 KB 或 MB最好用-k或-m强制指定。-m表示以 MB 为单位。iostat -x -t 1 5-t参数会在每行输出前显示当前时间。做问题记录和回溯时特别有用能让我知道某次高负载具体发生在哪个时间点。3.3 扩展模式下每个字段的含义执行iostat -x 1 1后设备部分的字段会多出很多看起来可能有点吓人但每一个字段背后都有实际意义字段含义判断要点rrqm/s每秒合并读请求数值高说明有大量相邻的读请求被合并不一定是坏事wrqm/s每秒合并写请求数文件系统合并写请求可减少磁盘寻道对机械盘有正向作用r/s每秒实际读请求次数看随机读压力的核心指标w/s每秒实际写请求次数看随机写压力的核心指标rkB/s每秒读取数据量KB与 r/s 结合可判断单次读大小wkB/s每秒写入数据量KB与 w/s 结合可判断单次写大小avgrq-sz平均每次 I/O 的数据大小扇区值偏小说明以小尺寸随机 I/O 为主通常对磁盘更不友好avgqu-sz平均 I/O 队列长度持续大于磁盘队列深度可能意味着磁盘饱和await平均每次 I/O 请求从提交到完成的时间毫秒包含排队时间和实际处理时间用户体感最直接r_await读请求平均等待时间毫秒专门看读延迟w_await写请求平均等待时间毫秒专门看写延迟svctm平均每次设备 I/O 操作的服务时间毫秒老版本指标接近磁盘本身处理能力但新内核已经弱化%util设备忙碌时间占比设备饱和度参考指标但需要结合队列深度理解这里面最容易引起误解的是svctm。在新版本 iostat 里svctm可能显示为 0 或者被移除原因是现代块设备有复杂的缓存和多队列调度机制单纯用“设备服务时间”描述已经不够准确。很多人还在用老思路看待 svctm这是需要更新的知识点。3.4 CPU 部分的快速判断avg-cpu部分里值得重点关注的是%iowait。它表示 CPU 等待磁盘 I/O 所花时间占整个时间周期的百分比。如果%iowait持续高于 10%就要注意磁盘是不是有点吃力了。不过这也不是绝对的——%iowait高只能说明 CPU 在等待 I/O 完成不能直接等价于磁盘 100% 繁忙。例如一个有大量并发写操作的系统即使磁盘已经忙不过来%iowait也可能并不高因为大量线程可能被阻塞在 D 状态不可中断睡眠而不是被统计到%iowait中。所以我的习惯是先看%iowait判断是否有 I/O 等待问题再看设备级指标做精确确认两者结合而不是只看一个项。4. 核心指标误区与磁盘性能评估思路4.1 %util 不是越低越好也不是越高越坏%util代表统计周期内有百分之多少的时间设备是忙碌的。比如 70% 意味着在统计周期内设备有 70% 的时间在处理请求30% 的时间是空闲的。直观理解确实如此但需要特别注意%util只是“设备忙的时间百分比”并不反映队列里等待了多少请求。在老式机械硬盘时代一块磁盘同时只能处理一个 I/O%util 接近 100% 基本就说明到极限了。但现代设备比如 NVMe SSD、云硬盘、硬件 RAID 卡通常支持多队列并行可以同时处理多个 I/O 请求。所以%util达到 100% 并不一定代表磁盘没有余量。反过来%util只有 30%也可能因为某几个大请求卡住了应用。看磁盘是否成为瓶颈我更建议结合avgqu-sz、await和%util三个值一起来判断。如果%util高、await高、avgqu-sz同时在持续增大那就是典型的“设备已经处理不过来了”如果%util高但await很低说明设备并发处理能力强虽然忙碌但响应速度依然很快可能还没到极限。4.2 为什么你会看到 %util 超过 100%我见过很多朋友在跑iostat -x时看到%util超过 100%比如 152% 甚至 200%然后以为工具出 bug 了。其实不是 bug。在多磁盘组成的 MD 设备、硬件 RAID 阵列、云盘这类支持并发请求的设备上%util的计算方式会导致它可能超过 100%。它表示的是请求占用了多少“设备的服务时间”对于有并行能力的设备来说某一秒内可能同时有 1.5 条请求在被处理于是数值超过 100。所以在实践里看到%util超过 100%我不建议直接断定磁盘“完蛋了”而是要去查avgqu-sz和await。如果await也在同步飙升说明并发请求真的太多、排队严重如果await很低那就说明设备的并行处理能力还在可以继续观察。4.3 随机 I/O 和顺序 I/O 对指标的影响同样一块磁盘跑顺序读写和随机读写iostat 显示的指标会有天壤之别。顺序读写时磁盘寻道时间少await可以很低rkB/s和wkB/s可以很高随机读写时则相反大量时间耗在寻道和旋转延迟上await会明显上升吞吐量反而下降。有一次我帮同事看一台机械盘服务器await一直在 80ms 左右他以为是磁盘快到寿命了。我让他跑了iostat -x 1观察发现r/s很高但rkB/s很低也就是说大量小尺寸随机读这正好解释了高延迟。这种性能问题不是磁盘坏而是应用访问模式导致。后面通过调整数据库缓存命中率把很多重复读取都挡在内存层面await迅速降了下来。4.4 估算磁盘最大吞吐能力的简单方法做性能基线时可以通过对比观测值来评估还有多少余量。例如一块云上标注 350MB/s 的 SSD线上正常业务读写总和在 120MB/s 左右那么剩下的空间还很大。但如果你拿到一块标称 350MB/s 的盘实际业务跑出来的写入速度只有 50MB/s且%util已到 90% 以上这就说明实际能用的吞吐远低于标配就要警惕云服务商给的是否是共享型资源。为验证真实能力我通常会在业务低峰期用fio做一轮基准测试把峰值写吞吐测出来再和 iostat 里的实际业务峰值对比这样就能清楚知道磁盘余量到底如何。5. 实战案例一次数据库慢查询引发的磁盘排查5.1 现象描述有一回一个内部系统的 MySQL 实例突然出现大量慢查询。开发那边看 SQL 并没有新增或变更索引也都正常于是怀疑是数据库参数问题。我登录服务器后第一件事就是执行iostat -x 1 10连续采集 10 秒数据后很快就发现了异常数据盘 vdb 的w/s一直在 500 到 800 之间波动wkB/s大概在 20000KB 到 40000KB 之间avgqu-sz持续接近 15w_await达到 50ms 以上%util在 85% 到 100% 之间。这个现象已经比较明确这台实例的磁盘写入压力非常大I/O 请求在排队磁盘成为瓶颈。5.2 排查过程进一步排查时我分了几步用mysqladmin processlist看数据库当前连接和线程状态发现不少线程处于Writing to net或Updating状态。用iostat -x 1 5 | grep vdb持续观察确认高写入并非偶发尖峰而是持续性的。检查 binlog 和事务日志发现开启了大事务批量更新操作并且 binlog 写入策略为同步模式。查看慢查询日志定位到某几张表存在频繁的UPDATE操作单次更新涉及大量行数据。综合这些信息我判断并非数据库参数异常而是磁盘层写能力跟不上业务写入需求。那台实例用的是普通高效云盘本身随机写入能力有限在高峰期出现排队是必然结果。5.3 解决方案和经验总结处理方案是临时的和长期的结合临时将 binlog 写入策略进行了适当调整并在业务侧对大事务做了拆分降低瞬时写入压力。长期上联系云平台对数据盘进行扩容和升级换到更高 I/O 能力的 SSD 类型同时在应用层做了缓存优化减少高频更新带来的写放大。这个案例让我形成了一个固定习惯遇到“应用变慢但 CPU 不高”的问题一定先跑iostat -x 1 5。如果磁盘的await高、%util高、avgqu-sz高那问题大概率在 I/O 层而不是业务代码。6. 进阶玩法把 iostat 用成持续监控工具6.1 周期性输出观察峰值规律单次执行 iostat 只能看到瞬间状态想要评估系统整体健康必须周期性采集。我最常用的命令是iostat -x -t 1 60 /tmp/iostat_$(date %Y%m%d_%H%M%S).log 这会在后台记录一分钟内每秒钟的磁盘状态。等业务流程出现卡顿后再打开日志查看当时的具体负载。这种方式的优点是零依赖、不侵入系统也不影响业务缺点是没有阈值告警能力需要人工事后分析。6.2 用脚本采集关键指标并落库如果你管理几十台服务器人工翻日志就不现实了。我写过一个简单的 shell 脚本定期抓取关键指标输出为 CSV 格式方便后续用 Excel 或 Grafana 分析。核心思路如下#!/bin/bash DISKvdb INTERVAL10 while true; do TIMESTAMP$(date %Y-%m-%d_%H:%M:%S) DATA$(iostat -x -k 1 1 | grep $DISK | tail -1) TS$(echo $DATA | awk {print $2}) KS$(echo $DATA | awk {print $3}) WA$(echo $DATA | awk {print $6}) UTIL$(echo $DATA | awk {print $12}) echo $TIMESTAMP,$TS,$KS,$WA,$UTIL disk_monitor.csv sleep $INTERVAL done这里我用 awk 从 iostat 输出里抽出tps、rkB/s、w_await、%util等字段。需要注意的是不同版本的 iostat 输出列顺序可能有差异脚本里硬编码列号前最好先手动跑一次确认字段位置。最保险的办法是使用关键字匹配比如用awk输出整行然后把字段名和值列成 JSON再解析到监控平台。6.3 和 vmstat、sar、pidstat 联动iostat 很强大但它只解决“磁盘层”的问题。想要完整定位一次性能故障我通常会同时开三个终端分别执行vmstat 1 60 iostat -x 1 60 pidstat -d 1 60vmstat用来观察内存、CPU 和系统级 I/O 等待。iostat用来观察磁盘设备层。pidstat -d用来定位到底是哪个进程在疯狂读写磁盘。这三者一组合就能回答三个连续问题系统有没有 I/O 问题哪块磁盘出问题是哪个进程导致的比如有一次我发现某块盘%util很高但数据库并不在这块盘上接着用pidstat -d才发现是日志清理程序和备份脚本同时跑把磁盘带宽抢光了。6.4 建立磁盘性能基线的建议监控的最大价值不仅是“故障时发现问题”而是“在故障发生前就识别风险”。我会在每台新服务器上线后先在正常业务负载下运行两到三天的 iostat 采集记录下常用的峰值和均值。例如某台机器正常业务下await通常小于 5ms%util不超过 20%。如果某一天%util突然持续到 80%即使业务用户还没感受到明显卡顿我也能提前准备扩容或优化方案。这个“基线思维”比任何高级技巧都重要。7. 常见问题与排查技巧实录7.1 iostat 常见问题速查表下面这些问题都是实际环境中反复出现过的我整理成一个速查表方便你在遇到时快速对照。问题现象可能原因解决方法提示command not foundsysstat 包未安装按系统安装 sysstat或源码编译只有 CPU 数据没有设备数据权限不足或没有块设备使用 root 执行或检查容器内是否映射了磁盘%util超过 100%设备支持并发多请求并行处理结合avgqu-sz和await综合判断不要直接判死svctm为 0新版本移除了该字段或设备不适用改用await和r_await、w_await判断响应延迟首次执行数值很大显示的是开机以来的平均值必须加时间间隔参数如iostat -x 1 5Docker 容器内看不到真实磁盘容器内看到的设备是宿主机共享的在宿主机上执行 iostat或用 cgroup 层面的 io 统计云盘延迟高但本机无异常网络存储受宿主机邻居影响多用几轮数据对比结合云平台监控确认输出单位不一致不同版本默认单位不同用-k或-m强制单位7.2 容器环境下 iostat 的局限性现在很多应用跑在 Docker 或 Kubernetes 里如果在容器里执行 iostat大概率看到的是宿主机层面的块设备信息而不是容器自身的 I/O 限制。容器里看到的同一个设备名实际反映的是宿主机整块磁盘的负载无法精确对应到当前容器。如果要做容器粒度的 I/O 监控更可靠的方案是读取/sys/fs/cgroup/blkio下的统计文件或者直接使用docker stats查看块 I/O 总量。不过这不代表 iostat 在容器环境没用——你仍然可以在宿主机上用它判断磁盘整体是否健康再把容器部署调度到健康节点上。7.3 几个我个人的实操心得第一iostat 的采样间隔建议选 1 秒采样次数不要太多。iostat -x 1 3是我排查问题时最常用的组合既能抓住实时变化又不会因为刷屏影响操作。第二注意区分kB_read/s和实际业务请求。高吞吐不等于高延迟关键是看await。有时候rkB/s已经 50MB/s但await只有 0.5ms说明设备响应很好反而不用担心。第三不同磁盘类型有完全不同的正常基准。机械盘await在 10-20ms 以内算正常云 SSD 通常在 1-5msNVMe 则可能 0.1ms 左右。建议在排查前先了解当前环境磁盘的预期性能否则很容易产生“误报警”。第四iostat 输出里Device列可能是dm-0、vda、sda或者nvme0n1等不同名字。当服务器有多个磁盘时先通过lsblk查看设备和挂载点对应关系避免盯错目标。7.4 两条能减少误判的具体技巧一条是不要只取第一次输出作为判断依据。iostat 第一次数据表示系统启动以来的均值必须等第二次、第三次数据出来后才反映真实负载。类似地如果只看一两秒很容易被瞬间尖峰误导采样建议至少 5 秒以上再下结论。另一条是结合错误日志一起判断。iostat 显示的高延迟可能来自磁盘坏道导致的反复重试此时系统日志/var/log/messages或dmesg里通常会有I/O error字样。有一次我发现某块盘await高得离谱排查时系统日志提示磁盘存在坏块才意识到不是负载问题而是物理硬件问题。光看 iostat 不结合系统日志很容易漏掉这种特殊情况。我在实际运维中有一个很深的体会iostat 这类工具真正用好的关键不在于背下所有参数而是看懂指标背后的因果关系。%util高不一定是磁盘坏await高也不一定代表磁盘在满负荷运转判断一次 I/O 问题一定要把设备层、进程层、访问模式结合起来看。尤其是碰到数据库等对延迟敏感的业务提前建立好 iostat 监控基线和自动采集脚本比每次故障时临时跑命令要有效得多。如果你刚接触 iostat建议先把iostat -x 1 5的输出逐字段研究透再对照实际业务验证很快就能建立自己的判断体系。