1. 定位与选型:三个命令到底分别解决什么问题先说个我踩过的坑。前几年有次线上数据库告警,存储响应变慢,所有查询像卡住一样。当时告警群里一个刚入职的同事把iostat、dstat、iotop三个命令挨个敲了一遍,输出贴了一屏,最后大家对着截图看了半天,也没得出结论。问题不在命令没执行,而在于三个工具的视角是完全不同的,用错了角度看输出,再多的数据也是噪音。这三个命令经常被放在一起提,但放在一起不代表它们是一回事。实际排查中,它们更像是一套层层递进的工具链:先有一个全局视角,再缩小到设备,最后锁定到进程。很多人上来就敲 iostat -x 1,然后盯着 %util 发懵,是因为跳过了前面的步骤,把“工具”用成了“数据源”,却不知道自己在找什么。如果你刚接触性能排查,我的建议是先把每个工具的定位记清楚:iostat 是看“磁盘设备”的,iotop 是看“进程行为”的,dstat 是看“系统整体资源联动”的。它们之间的区别不是参数多少的问题,而是回答的问题不同。1.1 磁盘性能排查的核心需求拆解做系统性能排查,本质上是在回答三个问题:瓶颈在哪里、为什么出现、是谁造成的。假设业务反馈“写入变慢了”。这个描述本身没有太多信息量。是CPU先满了,还是磁盘先满了?是单个磁盘设备达到了物理极限,还是某个进程疯狂读写把带宽吃光了?不同的问题对应不同的排查层次,也就需要不同的工具。我把排查思路拆成三层:第一层是系统资源总览。CPU、内存、磁盘、网络,谁先到瓶颈,占比多少,互相之间有没有关联。这层用 dstat 比较合适,一条命令能看到多个维度的实时变化。第二层是磁盘设备细节。排除掉CPU和内存的因素后,确认磁盘本身的IOPS、吞吐、等待时间和队列情况。这层用 iostat -x 能拿到很完整的数据。第三层是进程级定位。磁盘确认有问题后,要找出是谁在读写、读写量有多大、是持续行为还是瞬时突刺。这层交给 iotop 最顺手。这个分层思路,和网络排查中“先看整体丢包还是局部丢包、再定位到具体IP”是同一个逻辑。盲目执行工具没有任何意义,先想清楚当前处在哪一层。1.2 iostat:系统角度的磁盘健康报告iostat 是 sysstat 工具包里的核心成员,它从内核的块设备层收集统计信息,输出的是磁盘设备的吞吐量、IOPS、利用率、等待时间等指标。我用 iostat 用得最多的是它的扩展模式,也就是 iostat -x。这个模式下的数据非常接近磁盘的真实工作情况,你能看到每个设备的读请求合并速率(rrqm/s)、写请求合并速率(wrqm/s)、实际每秒读写次数(r/s、w/s)、吞吐量、平均I/O等待时间(await)、平均服务时间(svctm)以及设备利用率(%util)。需要特别提醒的是,%util 这个字段是很多人的误区。它不是磁盘“忙了百分之多少”,而是设备在处理I/O请求的时间占比。对于机械硬盘来说,这个指标大体能反映是否接近性能上限;但对于SSD或者带RAID卡的环境,队列机制会让 %util 长期保持100%,看起来吓人,实际设备仍然在正常工作。后面我会专门展开讲。1.3 iotop:进程角度的I/O行为追踪iotop 和 top 的交互方式很像,但它追踪的不是CPU和内存,而是每个进程(或者线程)的磁盘读写带宽和I/O等待占比。它以约1秒的刷新频率动态更新,可以直观看到当前哪些进程在大量读写磁盘。这个工具最典型的应用场景是:磁盘利用率已经很高,但不知道是谁干的。比如临时目录被某个后台批量任务狂刷,或者日志清理脚本在特定时间点触发全量扫描,都可能造成瞬时I/O风暴,用 iotop -o 看能一针见血。iotop 需要 root 权限,因为它要读取每个进程的I/O统计和调度信息,普通权限无法拿到完整数据,输出会不完整甚至直接报错。另外它的列比较多,SWAPIN 和 IO> 这两列很多人会看懵,后面我会做完整解释。1.4 dstat:全局资源联动的快照台dstat 是这三者里唯一能同时整合CPU、内存、磁盘、网络、系统负载等多项指标的工具,它的设计初衷是替代 vmstat、iostat、netstat 等命令的组合。实际使用中,我通常用 dstat 做快速健康体检。比如接到一个“机器性能差”的工单,我会先跑一条 dstat -tcdrns 1 5,5秒内把CPU、内存、磁盘、网络各自的实时状态和变化趋势全部拉出来。它能帮你快速排除掉大部分问题,把排查焦点缩小到某一个具体维度。dstat 还有一个很实用的能力是插件扩展,比如 --top-cpu、--top-bio、--top-latency 可以动态显示占用率最高的进程。这意味着从全局指标定位到异常进程,dstat 一条命令就能完成,效率和体验确实优于反复切换工具。不过要说句公道话,dstat 的上游项目已经停止维护了,新装系统时有些发行版默认源里可能找不到。如果你用的是较新版本的系统,装不上也不必纠结,用 iostat + vmstat + 其余系统自带工具组合,一样能达到同样的排查效果。工具是手段,思路才是根本。1.5 三个工具的选型对比速查先码一张对比表,方便直观理解和使用时快速查阅:对比维度iostatiotopdstat核心视角系统块设备层进程/线程级I/O多维度全局联动主要用途磁盘设备吞吐、IOPS、等待、利用率找出占用I/O的进程、观察进程读写速率快速体检CPU/内存/磁盘/网络等整体趋势关键参数-x -d -p -k-o -b -P -k -a-c -d -n -r -s --top-*权限要求部分数据需root必须root普通用户可看大部分输出模式循环多行统计动态交互界面/批处理表格刷新/CSV导出典型场景判断磁盘是否到瓶颈定位哪个进程在狂写先判断瓶颈在哪个维度2. 安装准备与最小可用实践2.1 不同系统下的安装命令三个工具的安装各有归属,先说明一下我常用来验证的环境配置,便于你对照。在Debian系的系统上,iostat 属于 sysstat 包,iotop 是独立包,dstat 以前在源里能直接装,现在新版可能需要从archive源或者用替代包。典型的安装命令:# Debian/Ubuntu系 apt update apt install sysstat iotop # dstat在部分新版源中已移除,如装不上可安装替代综合监控方案 apt install dstat在Red Hat系的系统上,sysstat 通常默认已安装,iotop 需要额外安装,dstat 在EPEL源里:# CentOS/RHEL系 yum install sysstat iotop yum install epel-release yum install dstat需要注意,新装完 sysstat 后,iostat 第一次运行可能需要等待系统收集一次统计数据,否则输出中会提示“-”或“0.00”,属于正常现象。另外部分版本的系统占用了系统资源统计的定时任务,需要确认 /etc/cron.d/sysstat 文件存在且权限正确,否则后续历史数据采集不到,iostat 首次展示的采样间隔可能和实际不符。2.2 iostat 最小用法与输出解读我最常用的最小命令是:iostat -d -k 1 3它的含义是:只看磁盘设备维度(-d),以KB为单位输出(-k),每1秒采样一次,总共输出3次。实际生产中,我会追加 -x 参数,因为 -x 扩展模式下包含的字段更丰富,判断价值更大:iostat -x -k 1 3输出大概长这样:Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util vda 0.00 0.00 0.00 1.67 0.00 16.00 19.20 0.13 78.00 0.00 78.00 1.00 16.70先别被这么多字段吓到,核心其实只有几个。r/s 是每秒实际读次数,w/s 是每秒实际写次数,rkB/s 和 wkB/s 是每秒读写多少KB,await 是I/O请求从提交到完成的总等待时间(包含在队列里的时间),svctm 是设备实际处理一个I/O请求的平均时间,%util 是设备忙的时间占比。如果 w/s 很大、await 也很大,但 %util 并不高,说明I/O请求大量堆积在等待队列中,设备本身可能不是瓶颈,瓶颈可能在调度层,也可能在下游链路。反过来,%util 长期接近100%,哪怕 await 数据看着一般,设备也已经接近饱和状态。这两个组合起来看,比单独看一个字段靠谱得多。2.3 iotop 最小用法iotop 的最小用法一条命令就够了:iotop -o-o 是 only 的意思,只显示真正发生了I/O的进程,默认界面不会刷出一堆零读写进程。等待几秒后,屏幕上会动态刷新,你能看到类似下面的界面布局:Total DISK READ: 0.00 M/s | Total DISK WRITE: 5.02 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 12345 be/4 root 0.00 B/s 5.02 M/s 0.00 % 0.50 % backup_script顶部两行是总和数据,下面每行对应一个进程或线程。DISK READ 和 DISK WRITE 列的单位默认根据数据量自动切换为 B/s 或 M/s,SWAPIN 表示进程从交换分区换入数据的耗时占比,IO> 表示进程等待I/O完成的时间占比。如果 SWAPIN 居高不下,大概率是内存不足导致频繁换页,这个锅不能甩给磁盘。我强烈建议在生产服务器上使用 iotop 时带上 -b 参数(batch模式),因为它不需要动态交互界面,可以直接把采样结果输出到日志文件里,事后慢慢分析:iotop -b -o -k -n 10 -d 2 > /tmp/iotop.log这段命令的意思是:批处理模式输出,只显示有I/O的进程,以KB为单位,总共采样10次,每次间隔2秒,结果落到 /tmp/iotop.log。这个玩法在排查“某个时段定时任务引发I/O突刺”时特别省事,可以先让命令跑着,该干嘛干嘛去。2.4 dstat 最小用法dstat 最省心的用法是:dstat -tcdrns 1 5参数拆开看:-t 印时间,-c CPU,-d 磁盘读写,-r 磁盘IOPS,-n 网络收发,-s 交换空间。1 5 表示每秒刷新一次、输出5组后自动退出。除去几个系统级别的初始化行,后续输出大概长这样:----system----|----total-cpu-usage----|-dsk/total-|-net/total-|---paging--|-system- time |usr sys idl wai stl| read writ| recv send| in out | int csw 12-01 10:00:01| 12 43 22 20 0|4096k 1024k| 10M 512k| 0 0 |3421 8912真正需要关注的是 wai(CPU等待I/O的占比)和 dsk(磁盘吞吐)。如果 wai 长期超过30%,基本可以断定I/O已经严重拖慢了CPU执行效率。这种情况在数据库服务器上尤其明显,查询请求到达后,CPU计算能力再好,也只能干等磁盘把数据取回来。dstat 也能玩出花活,比如直接用 --top-cpu 找出CPU占用最高的进程,用 --top-bio 找出块I/O最多的进程。在初期快速判断方向时,往往一条 dstat --top-bio 命令就把问题定位了大半。3. 核心参数深度解析:读透输出里的每个数字这一节没有花架子,全是硬通货。我会把三个工具在生产中真正用得上的参数和输出字段拆开讲,附带上个人经验里的判断阈值和取舍逻辑。3.1 iostat 扩展数据下的关键字段与实际判读逻辑先把我最常盯的几个字段拉出来,逐个说清楚。r/s 和 w/s 分别是每秒读请求次数和每秒写请求次数。注意这里的“请求次数”是设备层实际收到的I/O请求数,它和业务层的逻辑读次数是不同的。数据库领域的“每秒查询数”可能非常高,但经过页缓存、块合并之后,落到设备层的 r/s 可能并不夸张。因此分析时一定要看设备层数据本身。rkB/s 和 wkB/s 是每秒实际读写的字节数。这两个字段通常和 r/s、w/s 一起看,能算出平均每个请求的数据量(avgrq-sz)。如果请求次数很高但每次请求数据量很小,说明系统在做大量随机小I/O访问;如果请求次数不高但单次数据量很大,大概率是顺序读写。随机小I/O和顺序大I/O对磁盘性能的影响完全不同,对应用层的优化方向也完全不同。举个例子:avgrq-sz 如果长期低于16KB,说明请求非常碎片化,应用可能在高频读取小文件或者某些存储引擎的行级更新没有充分合并;如果持续高于64KB甚至128KB,那基本可以确定是顺序扫描或日志类追加写入。搞清楚这个区别,再去调应用层参数,方向感会清晰很多。await 和 r_await、w_await 这组字段尤其重要。await 是所有I/O请求从进入等待队列到实际完成所花时间的平均值,包含排队时间和服务时间。r_await、w_await 分别拆开看读和写。生产环境里,机械硬盘的 await 在5~20毫秒属于正常范围,超过20毫秒就要警惕,超过100毫秒基本可以认定为故障级别;SSD 的正常范围会低一个数量级,通常在1~3毫秒以内。但单单看 await 不够,还要结合 svctm。svctm 是设备处理单个请求的平均时间,它不包含排队时间。如果 await 远大于 svctm,说明大量时间消耗在排队上,意味着队列已经过长,设备繁忙或底层架构有瓶颈。如果 await 和 svctm 差不多,说明请求基本不需要排队,设备处理速度本身暂时够用。%util 是我用了很多年后才真正理解透彻的指标。它的定义是设备忙于服务I/O请求的时间占总时间的百分比。如果设备存在多个并发请求同时处理的能力,比如SSD的内部并行、RAID的多盘并发,%util 的计算方式就会让它长时间处于虚高状态。不要一看到 %util 100% 就判定磁盘满负荷,一定先看 svctm 是否异常放大、await 是否超过正常水平。我见过不少SSD环境 %util 常年100%,但业务毫无感知的情况,这就是典型的指标误读。还有个容易忽略的字段 avgqu-sz,表示设备队列的平均长度。如果这个值长期大于几甚至几十,说明请求堆积已经很严重了。对于机械磁盘,队列长度保持在1以下比较健康;超过2~4就需要关注。SSD环境下队列本身较深,这个字段建议和 await 一起联动判断,单看没有绝对阈值。3.2 iotop 界面字段全解及批处理模式的核心价值iotop 交互界面里,除了 TID、USER、COMMAND 这些一眼能看懂的字段,最让人犯迷糊的是 SWAPIN 和 IO>。我先细说这两个。SWAPIN 表示进程在等待从交换分区换入内存的时间占比。这个数值高,大概率不是磁盘I/O的问题,而是物理内存紧张,系统在频繁换页把进程数据在内存和磁盘之间搬来搬去。处理思路是加内存,或者排查进程是否存在内存泄漏,而不是盯着磁盘设备发愁。IO> 是进程等待块I/O完成的时间占比,它是判断进程是否被I/O卡住的关键指标。如果某个进程的 IO> 长期维持在50%以上,说明它过半的时间都在等磁盘响应,业务变慢的根因就此浮出水面。我实际用得最多的场景是这样的:应用反馈批量任务执行时间异常拉长,现象是偶发性的。我先用 iotop -b -o -k -n 30 -d 3 采样90秒,生成一份完整日志,再观察输出里的变化规律。如果某个进程每周固定时间点出现高DISK WRITE,查看计划任务就发现是周期性的全量索引重建;如果随机出现,排查对象就要扩大到定时清理、临时表操作等不确定因素。还有一个实用的参数是 -P,它只显示进程而不展开线程。默认情况下 iotop 会把每个线程作为一行输出,一个多线程应用可能刷出几十行,影响看图效果。加了 -P 后,所有线程汇总到进程维度,界面清爽很多。缺点是如果问题是由某个特定线程引起的,线程级信息就看不到了,所以我通常先用线程级模式观察,确认范围后再用 -P 做汇总评估。3.3 dstat 常用参数组合及插件玩法的选择策略dstat 的常规参数可以自由组合,我按使用场景列几个高频组合:# 快速健康体检,覆盖CPU/磁盘/网络/交换分区 dstat -tcdrns 1 10 # 只看磁盘I/O,并找出块I/O占用最高的进程 dstat -d --top-bio 1 10 # 观察文件系统缓存和CPU等待之间的关系 dstat -c --top-cpu --top-io 1 10 # 导出CSV,方便事后用工具分析作图 dstat -tcdrns --output /tmp/disk_analysis.csv 1 60为什么我这么重视 --top-bio 这个插件?因为在实际定位问题的时候,最难的不是看出磁盘忙,而是找出谁让磁盘忙。dstat 默认输出不包含进程信息,如果不依靠插件,你还得再开一个 iotop 的窗口去对照时间。而 --top-bio 直接在表格下方列出当前采样周期内块I/O占用最高的进程,一步到位。还有一组参数组合我经常用在工作交接场景:dstat -tcdrns --output report.csv 1 120。跑两分钟,导出一份CSV,随后用表格工具打开,选中 wai 和 dsk 两列画折线图。图表一拉出来,瓶颈在哪、什么时间段开始突刺,一眼就清楚了,跟同事或上级解释起来也直观得多。自己会看输出是一回事,能让别人看懂是另一回事。用 dstat 导出CSV做可视化,是让汇报不费劲的好习惯。4. 一次完整的I/O瓶颈排查实战案例光讲命令行输出不实战,等于纸上谈兵。这一节用我印象比较深的一次真实排查经历来做完整演示。出于合规考虑,这里使用虚构代号“某业务系统”,但排查过程和数值都是实际经历浓缩提炼的。4.1 案例背景与初步现象某业务系统部署在单机服务器上,承载基础数据同步任务。某天监控平台连续推送告警,提示磁盘I/O等待时间高、应用响应延迟明显上升。故障出现在晚间8点左右,持续时间不固定,有时十几分钟自动恢复,有时需要重启应用才能恢复。登入服务器后,我第一步没有直接跑任何工具,而是先了解两个背景信息:机器本身的硬件配置(磁盘类型、容量、是否RAID)以及业务方最近是否有变更发布。确认硬件是普通SSD且没有RAID保护后,我意识到如果I/O持续饱和,损伤的可能不仅是性能,还有硬件寿命,所以排查优先级比较高。4.2 第一层:dstat 快速判定瓶颈维度执行命令:dstat -tcdrns 1 10输出显示:CPU 的 wai(wait for I/O)列跳跃到20%~35%,usr 和 sys 相对平稳。磁盘 dsk/writ 在故障发生时段飙到 80MB/s 以上,网络收发却很低。到这里我已经得出结论:问题不在网络,不在CPU计算能力,而是确确实实有进程在大量写盘。wai 明显偏高,代表CPU有大量时间在等I/O,应用响应变慢是磁盘拖累的结果。4.3 第二层:iostat 确认是哪个磁盘设备在承受压力执行命令:iostat -x -k 1 5输出中,数据盘 sdb 的数据非常扎眼:Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sdb 0.0 450.0 0.3 320.0 4.0K 80.0M 256.0 4.5 25.0 2.0 26.0 2.5 99.8重点解读:w/s 高达320,基本上是进程在不停发写请求;wkB/s 80MB,这是大块顺序写;avgrq-sz 256KB,每次请求数据量非常大;await 25ms 对SSD来说明显偏高了;%util 99.8%。综合来看,sdb 已经持续承接高负载的顺序写入,但SSD的写入寿命在这种强度下消耗很快。和上一节讲到的判断逻辑连起来:大量顺序写说明不是碎片化随机访问,更像日志落盘或数据导出。接下来需要知道这个写进程到底是谁。4.4 第三层:iotop 锁定元凶进程执行命令:iotop -b -o -k -n 5 -d 2输出很快就锁定了目标:一个名为 sync_data 的Java后台进程,每次刷新都占据大量DISK WRITE,单进程写速率在60~90MB/s,IO> 列达到30%~50%。结合业务变更记录,当天下午某部门发布了一个参数调整,svn版本历史里正好包括这个模块的配置变更,时间轴完全吻合。再追一下命令细节,发现该进程内部启动了一个数据全量导出任务。原本的增量同步逻辑被一次全量数据变更触发,导致数据文件和日志同时大量写盘。这就是故障的完整链路。4.5 处置措施与最终验证定位到具体进程后,我的处置方案分三步走:第一,用 ionice 将同步任务的I/O优先级调低,避免它和主业务争抢磁盘带宽。比如给该进程设置了 idle 级别,让它只在磁盘空闲时执行读写。要注意的是 ionice 的生效依赖进程所属的I/O调度器支持,CentOS 7 等系统的默认调度器同时支持最佳尝试和限制类型,使用前先确认当前调度器类型:cat /sys/block/sdb/queue/scheduler第二,和业务方确认该全量导出任务能否放到业务低峰期执行。经过沟通,运维侧把任务启动时间调整到凌晨2点,避开晚间的主业务高峰。第三,持续观察一段时间。切换后的第一个完整周期里,再次用 iostat -x 监控 sdb,%util 已从99.8%降到35%以下,wai 也回落到了5%以内,应用响应时间恢复正常。这次排查从头到尾用的就是 dstat 看全局、iostat 看设备、iotop 找进程三层套路,排查时间压缩在20分钟以内。如果一开始就只盯着 iostat 盲目分析,不知道第二层还应该往进程层深挖,恐怕还要折腾大半天。5. 高频故障与避坑要点速查5.1 常见误判场景汇总根据我多年处理系统性能问题的经验,把最常见的问题、容易误判的原因和对应的正确思路整理成一张速查表:现象常见误判正确排查思路%util 长期100%磁盘一定挂了结合 svctm、await、avgqu-sz 判断是否真的队列饱和,SSD场景尤其要谨慎await 高磁盘硬件差先区分是排队时间高还是服务时间高,await 减去 svctm 大致就是排队时间SWAPIN 高磁盘I/O瓶颈优先查内存容量和进程内存占用,可能是频繁换页导致,并不是磁盘本身慢dstat 显示 dsk 高但 iotop 无异常工具统计口径不一致确认是否非进程直接写盘,比如文件系统缓存回写、内部线程刷新,用 iotop -a 看累计量定时任务导致偶发I/O尖峰难以复现,不了了之用 iotop -b 和 dstat 同时采样并导日志,等下次任务触发时归档分析5.2 排查过程中容易被忽略的细节有些细节,平时不遇到根本不会想到,等遇到了发现已经绕了弯路。我挑几个亲历过的点分享一下。第一,采样间隔和采样次数设置不合理,会导致结果失真。iostat 默认不带间隔参数时只输出一次自启动以来的平均数据,这对于定位当前实时问题基本没用。至少设置 1 秒间隔,连续采集5到10次,才能捕捉到当前的波动状态。dstat 和 iotop 也一样,间隔太短比如0.1秒,输出反而会被高频刷新刷得眼花缭乱,建议最少1秒。第二,工具本身的权限限制。iotop 在非root用户下直接运行,会提示无法获取内核数据,输出不完整。如果你习惯用普通用户排查,记得先 sudo。iostat 的扩展模式部分数据也需要特权,生产环境请提前和运维确认好个人账号的提权方式,别等故障发生了现场抓瞎。第三,文件系统缓存(page cache)对数据的影响。Linux 会尽量把读请求缓存在内存中,读操作很多情况下根本不会到达磁盘设备。因此你看到磁盘读很高时,先想想是否有进程绕过了缓存直接读盘,比如使用了 O_DIRECT 的数据库文件读取,这时候 iostat 显示的 r/s 才是真实的物理读。第四,工具版本差异可能导致字段含义不完全一致。比如 dstat 高版本对网络字段的展示方式有调整,老版本里 net/total 显示的是流量总量,新版本某些发行版的包管理定义为流量速率。遇到输出对不上的情况,先执行命令确认当前版本,再下结论。第五,生产环境千万谨慎使用 ionice 直接调整PID的I/O优先级,尤其不要远程操作后立刻断开会话,因为如果调度器不支持相应优先级或业务脚本自身修改了优先级,结果可能和你预期相反。建议先在测试环境验证规则,再在生产执行,执行后至少观察一轮业务周期。5.3 三个工具的配合套路与我的个人习惯如果你完整读到了这里,说明你对这套排查工具是真的感兴趣。我再分享一套我自己用得特别顺手的配合套路。接到性能类问题工单后,我习惯用两步走定位策略:先用 dstat 快速扫描全局资源,把瓶颈维度锁定到磁盘I/O;然后用 iostat -x 和 iotop 双管齐下,一个看设备数据、一个看进程行为,两边对照。iostat 说“磁盘忙”,iotop 说“是哪个进程让它忙”,两者交叉验证,结论基本不会跑偏。如果是周期性故障,比如业务方反馈每天某个时间段都会卡顿,我反而不会实时蹲守。我会在计划任务里县前预置一段采集脚本,把 dstat 和 iotop 的日志自动记录到文件,第二天直接分析故障窗口期的数据。这种“先埋点,后复盘”的方式,在非实时场景下比手工执行命令高效得多。还有一点是不要过早下结论。我看过很多人用 iostat 看到 %util 高就立刻判定“磁盘性能不足”,然后开始提硬件扩容工单。建议一定要结合后续的 iotop 检查,因为有些时候是某个进程发起的低效随机读写导致,真实业务量根本不高。换硬件是成本最高的手段,应该放在所有优化手段之后。排查性能问题,本质上是一次循证的过程。三个命令的合理组合使用,配合冷静的逐步拆解,绝大多数磁盘I/O故障都能在半小时内定位成因。工具始终只是工具,真正值钱的是面对指标时脑中那条清晰的排查链路。
1. 定位与选型:三个命令到底分别解决什么问题先说个我踩过的坑。前几年有次线上数据库告警,存储响应变慢,所有查询像卡住一样。当时告警群里一个刚入职的同事把iostat、dstat、iotop三个命令挨个敲了一遍,输出贴了一屏,最后大家对着截图看了半天,也没得出结论。问题不在命令没执行,而在于三个工具的视角是完全不同的,用错了角度看输出,再多的数据也是噪音。这三个命令经常被放在一起提,但放在一起不代表它们是一回事。实际排查中,它们更像是一套层层递进的工具链:先有一个全局视角,再缩小到设备,最后锁定到进程。很多人上来就敲 iostat -x 1,然后盯着 %util 发懵,是因为跳过了前面的步骤,把“工具”用成了“数据源”,却不知道自己在找什么。如果你刚接触性能排查,我的建议是先把每个工具的定位记清楚:iostat 是看“磁盘设备”的,iotop 是看“进程行为”的,dstat 是看“系统整体资源联动”的。它们之间的区别不是参数多少的问题,而是回答的问题不同。1.1 磁盘性能排查的核心需求拆解做系统性能排查,本质上是在回答三个问题:瓶颈在哪里、为什么出现、是谁造成的。假设业务反馈“写入变慢了”。这个描述本身没有太多信息量。是CPU先满了,还是磁盘先满了?是单个磁盘设备达到了物理极限,还是某个进程疯狂读写把带宽吃光了?不同的问题对应不同的排查层次,也就需要不同的工具。我把排查思路拆成三层:第一层是系统资源总览。CPU、内存、磁盘、网络,谁先到瓶颈,占比多少,互相之间有没有关联。这层用 dstat 比较合适,一条命令能看到多个维度的实时变化。第二层是磁盘设备细节。排除掉CPU和内存的因素后,确认磁盘本身的IOPS、吞吐、等待时间和队列情况。这层用 iostat -x 能拿到很完整的数据。第三层是进程级定位。磁盘确认有问题后,要找出是谁在读写、读写量有多大、是持续行为还是瞬时突刺。这层交给 iotop 最顺手。这个分层思路,和网络排查中“先看整体丢包还是局部丢包、再定位到具体IP”是同一个逻辑。盲目执行工具没有任何意义,先想清楚当前处在哪一层。1.2 iostat:系统角度的磁盘健康报告iostat 是 sysstat 工具包里的核心成员,它从内核的块设备层收集统计信息,输出的是磁盘设备的吞吐量、IOPS、利用率、等待时间等指标。我用 iostat 用得最多的是它的扩展模式,也就是 iostat -x。这个模式下的数据非常接近磁盘的真实工作情况,你能看到每个设备的读请求合并速率(rrqm/s)、写请求合并速率(wrqm/s)、实际每秒读写次数(r/s、w/s)、吞吐量、平均I/O等待时间(await)、平均服务时间(svctm)以及设备利用率(%util)。需要特别提醒的是,%util 这个字段是很多人的误区。它不是磁盘“忙了百分之多少”,而是设备在处理I/O请求的时间占比。对于机械硬盘来说,这个指标大体能反映是否接近性能上限;但对于SSD或者带RAID卡的环境,队列机制会让 %util 长期保持100%,看起来吓人,实际设备仍然在正常工作。后面我会专门展开讲。1.3 iotop:进程角度的I/O行为追踪iotop 和 top 的交互方式很像,但它追踪的不是CPU和内存,而是每个进程(或者线程)的磁盘读写带宽和I/O等待占比。它以约1秒的刷新频率动态更新,可以直观看到当前哪些进程在大量读写磁盘。这个工具最典型的应用场景是:磁盘利用率已经很高,但不知道是谁干的。比如临时目录被某个后台批量任务狂刷,或者日志清理脚本在特定时间点触发全量扫描,都可能造成瞬时I/O风暴,用 iotop -o 看能一针见血。iotop 需要 root 权限,因为它要读取每个进程的I/O统计和调度信息,普通权限无法拿到完整数据,输出会不完整甚至直接报错。另外它的列比较多,SWAPIN 和 IO> 这两列很多人会看懵,后面我会做完整解释。1.4 dstat:全局资源联动的快照台dstat 是这三者里唯一能同时整合CPU、内存、磁盘、网络、系统负载等多项指标的工具,它的设计初衷是替代 vmstat、iostat、netstat 等命令的组合。实际使用中,我通常用 dstat 做快速健康体检。比如接到一个“机器性能差”的工单,我会先跑一条 dstat -tcdrns 1 5,5秒内把CPU、内存、磁盘、网络各自的实时状态和变化趋势全部拉出来。它能帮你快速排除掉大部分问题,把排查焦点缩小到某一个具体维度。dstat 还有一个很实用的能力是插件扩展,比如 --top-cpu、--top-bio、--top-latency 可以动态显示占用率最高的进程。这意味着从全局指标定位到异常进程,dstat 一条命令就能完成,效率和体验确实优于反复切换工具。不过要说句公道话,dstat 的上游项目已经停止维护了,新装系统时有些发行版默认源里可能找不到。如果你用的是较新版本的系统,装不上也不必纠结,用 iostat + vmstat + 其余系统自带工具组合,一样能达到同样的排查效果。工具是手段,思路才是根本。1.5 三个工具的选型对比速查先码一张对比表,方便直观理解和使用时快速查阅:对比维度iostatiotopdstat核心视角系统块设备层进程/线程级I/O多维度全局联动主要用途磁盘设备吞吐、IOPS、等待、利用率找出占用I/O的进程、观察进程读写速率快速体检CPU/内存/磁盘/网络等整体趋势关键参数-x -d -p -k-o -b -P -k -a-c -d -n -r -s --top-*权限要求部分数据需root必须root普通用户可看大部分输出模式循环多行统计动态交互界面/批处理表格刷新/CSV导出典型场景判断磁盘是否到瓶颈定位哪个进程在狂写先判断瓶颈在哪个维度2. 安装准备与最小可用实践2.1 不同系统下的安装命令三个工具的安装各有归属,先说明一下我常用来验证的环境配置,便于你对照。在Debian系的系统上,iostat 属于 sysstat 包,iotop 是独立包,dstat 以前在源里能直接装,现在新版可能需要从archive源或者用替代包。典型的安装命令:# Debian/Ubuntu系 apt update apt install sysstat iotop # dstat在部分新版源中已移除,如装不上可安装替代综合监控方案 apt install dstat在Red Hat系的系统上,sysstat 通常默认已安装,iotop 需要额外安装,dstat 在EPEL源里:# CentOS/RHEL系 yum install sysstat iotop yum install epel-release yum install dstat需要注意,新装完 sysstat 后,iostat 第一次运行可能需要等待系统收集一次统计数据,否则输出中会提示“-”或“0.00”,属于正常现象。另外部分版本的系统占用了系统资源统计的定时任务,需要确认 /etc/cron.d/sysstat 文件存在且权限正确,否则后续历史数据采集不到,iostat 首次展示的采样间隔可能和实际不符。2.2 iostat 最小用法与输出解读我最常用的最小命令是:iostat -d -k 1 3它的含义是:只看磁盘设备维度(-d),以KB为单位输出(-k),每1秒采样一次,总共输出3次。实际生产中,我会追加 -x 参数,因为 -x 扩展模式下包含的字段更丰富,判断价值更大:iostat -x -k 1 3输出大概长这样:Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util vda 0.00 0.00 0.00 1.67 0.00 16.00 19.20 0.13 78.00 0.00 78.00 1.00 16.70先别被这么多字段吓到,核心其实只有几个。r/s 是每秒实际读次数,w/s 是每秒实际写次数,rkB/s 和 wkB/s 是每秒读写多少KB,await 是I/O请求从提交到完成的总等待时间(包含在队列里的时间),svctm 是设备实际处理一个I/O请求的平均时间,%util 是设备忙的时间占比。如果 w/s 很大、await 也很大,但 %util 并不高,说明I/O请求大量堆积在等待队列中,设备本身可能不是瓶颈,瓶颈可能在调度层,也可能在下游链路。反过来,%util 长期接近100%,哪怕 await 数据看着一般,设备也已经接近饱和状态。这两个组合起来看,比单独看一个字段靠谱得多。2.3 iotop 最小用法iotop 的最小用法一条命令就够了:iotop -o-o 是 only 的意思,只显示真正发生了I/O的进程,默认界面不会刷出一堆零读写进程。等待几秒后,屏幕上会动态刷新,你能看到类似下面的界面布局:Total DISK READ: 0.00 M/s | Total DISK WRITE: 5.02 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 12345 be/4 root 0.00 B/s 5.02 M/s 0.00 % 0.50 % backup_script顶部两行是总和数据,下面每行对应一个进程或线程。DISK READ 和 DISK WRITE 列的单位默认根据数据量自动切换为 B/s 或 M/s,SWAPIN 表示进程从交换分区换入数据的耗时占比,IO> 表示进程等待I/O完成的时间占比。如果 SWAPIN 居高不下,大概率是内存不足导致频繁换页,这个锅不能甩给磁盘。我强烈建议在生产服务器上使用 iotop 时带上 -b 参数(batch模式),因为它不需要动态交互界面,可以直接把采样结果输出到日志文件里,事后慢慢分析:iotop -b -o -k -n 10 -d 2 > /tmp/iotop.log这段命令的意思是:批处理模式输出,只显示有I/O的进程,以KB为单位,总共采样10次,每次间隔2秒,结果落到 /tmp/iotop.log。这个玩法在排查“某个时段定时任务引发I/O突刺”时特别省事,可以先让命令跑着,该干嘛干嘛去。2.4 dstat 最小用法dstat 最省心的用法是:dstat -tcdrns 1 5参数拆开看:-t 印时间,-c CPU,-d 磁盘读写,-r 磁盘IOPS,-n 网络收发,-s 交换空间。1 5 表示每秒刷新一次、输出5组后自动退出。除去几个系统级别的初始化行,后续输出大概长这样:----system----|----total-cpu-usage----|-dsk/total-|-net/total-|---paging--|-system- time |usr sys idl wai stl| read writ| recv send| in out | int csw 12-01 10:00:01| 12 43 22 20 0|4096k 1024k| 10M 512k| 0 0 |3421 8912真正需要关注的是 wai(CPU等待I/O的占比)和 dsk(磁盘吞吐)。如果 wai 长期超过30%,基本可以断定I/O已经严重拖慢了CPU执行效率。这种情况在数据库服务器上尤其明显,查询请求到达后,CPU计算能力再好,也只能干等磁盘把数据取回来。dstat 也能玩出花活,比如直接用 --top-cpu 找出CPU占用最高的进程,用 --top-bio 找出块I/O最多的进程。在初期快速判断方向时,往往一条 dstat --top-bio 命令就把问题定位了大半。3. 核心参数深度解析:读透输出里的每个数字这一节没有花架子,全是硬通货。我会把三个工具在生产中真正用得上的参数和输出字段拆开讲,附带上个人经验里的判断阈值和取舍逻辑。3.1 iostat 扩展数据下的关键字段与实际判读逻辑先把我最常盯的几个字段拉出来,逐个说清楚。r/s 和 w/s 分别是每秒读请求次数和每秒写请求次数。注意这里的“请求次数”是设备层实际收到的I/O请求数,它和业务层的逻辑读次数是不同的。数据库领域的“每秒查询数”可能非常高,但经过页缓存、块合并之后,落到设备层的 r/s 可能并不夸张。因此分析时一定要看设备层数据本身。rkB/s 和 wkB/s 是每秒实际读写的字节数。这两个字段通常和 r/s、w/s 一起看,能算出平均每个请求的数据量(avgrq-sz)。如果请求次数很高但每次请求数据量很小,说明系统在做大量随机小I/O访问;如果请求次数不高但单次数据量很大,大概率是顺序读写。随机小I/O和顺序大I/O对磁盘性能的影响完全不同,对应用层的优化方向也完全不同。举个例子:avgrq-sz 如果长期低于16KB,说明请求非常碎片化,应用可能在高频读取小文件或者某些存储引擎的行级更新没有充分合并;如果持续高于64KB甚至128KB,那基本可以确定是顺序扫描或日志类追加写入。搞清楚这个区别,再去调应用层参数,方向感会清晰很多。await 和 r_await、w_await 这组字段尤其重要。await 是所有I/O请求从进入等待队列到实际完成所花时间的平均值,包含排队时间和服务时间。r_await、w_await 分别拆开看读和写。生产环境里,机械硬盘的 await 在5~20毫秒属于正常范围,超过20毫秒就要警惕,超过100毫秒基本可以认定为故障级别;SSD 的正常范围会低一个数量级,通常在1~3毫秒以内。但单单看 await 不够,还要结合 svctm。svctm 是设备处理单个请求的平均时间,它不包含排队时间。如果 await 远大于 svctm,说明大量时间消耗在排队上,意味着队列已经过长,设备繁忙或底层架构有瓶颈。如果 await 和 svctm 差不多,说明请求基本不需要排队,设备处理速度本身暂时够用。%util 是我用了很多年后才真正理解透彻的指标。它的定义是设备忙于服务I/O请求的时间占总时间的百分比。如果设备存在多个并发请求同时处理的能力,比如SSD的内部并行、RAID的多盘并发,%util 的计算方式就会让它长时间处于虚高状态。不要一看到 %util 100% 就判定磁盘满负荷,一定先看 svctm 是否异常放大、await 是否超过正常水平。我见过不少SSD环境 %util 常年100%,但业务毫无感知的情况,这就是典型的指标误读。还有个容易忽略的字段 avgqu-sz,表示设备队列的平均长度。如果这个值长期大于几甚至几十,说明请求堆积已经很严重了。对于机械磁盘,队列长度保持在1以下比较健康;超过2~4就需要关注。SSD环境下队列本身较深,这个字段建议和 await 一起联动判断,单看没有绝对阈值。3.2 iotop 界面字段全解及批处理模式的核心价值iotop 交互界面里,除了 TID、USER、COMMAND 这些一眼能看懂的字段,最让人犯迷糊的是 SWAPIN 和 IO>。我先细说这两个。SWAPIN 表示进程在等待从交换分区换入内存的时间占比。这个数值高,大概率不是磁盘I/O的问题,而是物理内存紧张,系统在频繁换页把进程数据在内存和磁盘之间搬来搬去。处理思路是加内存,或者排查进程是否存在内存泄漏,而不是盯着磁盘设备发愁。IO> 是进程等待块I/O完成的时间占比,它是判断进程是否被I/O卡住的关键指标。如果某个进程的 IO> 长期维持在50%以上,说明它过半的时间都在等磁盘响应,业务变慢的根因就此浮出水面。我实际用得最多的场景是这样的:应用反馈批量任务执行时间异常拉长,现象是偶发性的。我先用 iotop -b -o -k -n 30 -d 3 采样90秒,生成一份完整日志,再观察输出里的变化规律。如果某个进程每周固定时间点出现高DISK WRITE,查看计划任务就发现是周期性的全量索引重建;如果随机出现,排查对象就要扩大到定时清理、临时表操作等不确定因素。还有一个实用的参数是 -P,它只显示进程而不展开线程。默认情况下 iotop 会把每个线程作为一行输出,一个多线程应用可能刷出几十行,影响看图效果。加了 -P 后,所有线程汇总到进程维度,界面清爽很多。缺点是如果问题是由某个特定线程引起的,线程级信息就看不到了,所以我通常先用线程级模式观察,确认范围后再用 -P 做汇总评估。3.3 dstat 常用参数组合及插件玩法的选择策略dstat 的常规参数可以自由组合,我按使用场景列几个高频组合:# 快速健康体检,覆盖CPU/磁盘/网络/交换分区 dstat -tcdrns 1 10 # 只看磁盘I/O,并找出块I/O占用最高的进程 dstat -d --top-bio 1 10 # 观察文件系统缓存和CPU等待之间的关系 dstat -c --top-cpu --top-io 1 10 # 导出CSV,方便事后用工具分析作图 dstat -tcdrns --output /tmp/disk_analysis.csv 1 60为什么我这么重视 --top-bio 这个插件?因为在实际定位问题的时候,最难的不是看出磁盘忙,而是找出谁让磁盘忙。dstat 默认输出不包含进程信息,如果不依靠插件,你还得再开一个 iotop 的窗口去对照时间。而 --top-bio 直接在表格下方列出当前采样周期内块I/O占用最高的进程,一步到位。还有一组参数组合我经常用在工作交接场景:dstat -tcdrns --output report.csv 1 120。跑两分钟,导出一份CSV,随后用表格工具打开,选中 wai 和 dsk 两列画折线图。图表一拉出来,瓶颈在哪、什么时间段开始突刺,一眼就清楚了,跟同事或上级解释起来也直观得多。自己会看输出是一回事,能让别人看懂是另一回事。用 dstat 导出CSV做可视化,是让汇报不费劲的好习惯。4. 一次完整的I/O瓶颈排查实战案例光讲命令行输出不实战,等于纸上谈兵。这一节用我印象比较深的一次真实排查经历来做完整演示。出于合规考虑,这里使用虚构代号“某业务系统”,但排查过程和数值都是实际经历浓缩提炼的。4.1 案例背景与初步现象某业务系统部署在单机服务器上,承载基础数据同步任务。某天监控平台连续推送告警,提示磁盘I/O等待时间高、应用响应延迟明显上升。故障出现在晚间8点左右,持续时间不固定,有时十几分钟自动恢复,有时需要重启应用才能恢复。登入服务器后,我第一步没有直接跑任何工具,而是先了解两个背景信息:机器本身的硬件配置(磁盘类型、容量、是否RAID)以及业务方最近是否有变更发布。确认硬件是普通SSD且没有RAID保护后,我意识到如果I/O持续饱和,损伤的可能不仅是性能,还有硬件寿命,所以排查优先级比较高。4.2 第一层:dstat 快速判定瓶颈维度执行命令:dstat -tcdrns 1 10输出显示:CPU 的 wai(wait for I/O)列跳跃到20%~35%,usr 和 sys 相对平稳。磁盘 dsk/writ 在故障发生时段飙到 80MB/s 以上,网络收发却很低。到这里我已经得出结论:问题不在网络,不在CPU计算能力,而是确确实实有进程在大量写盘。wai 明显偏高,代表CPU有大量时间在等I/O,应用响应变慢是磁盘拖累的结果。4.3 第二层:iostat 确认是哪个磁盘设备在承受压力执行命令:iostat -x -k 1 5输出中,数据盘 sdb 的数据非常扎眼:Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sdb 0.0 450.0 0.3 320.0 4.0K 80.0M 256.0 4.5 25.0 2.0 26.0 2.5 99.8重点解读:w/s 高达320,基本上是进程在不停发写请求;wkB/s 80MB,这是大块顺序写;avgrq-sz 256KB,每次请求数据量非常大;await 25ms 对SSD来说明显偏高了;%util 99.8%。综合来看,sdb 已经持续承接高负载的顺序写入,但SSD的写入寿命在这种强度下消耗很快。和上一节讲到的判断逻辑连起来:大量顺序写说明不是碎片化随机访问,更像日志落盘或数据导出。接下来需要知道这个写进程到底是谁。4.4 第三层:iotop 锁定元凶进程执行命令:iotop -b -o -k -n 5 -d 2输出很快就锁定了目标:一个名为 sync_data 的Java后台进程,每次刷新都占据大量DISK WRITE,单进程写速率在60~90MB/s,IO> 列达到30%~50%。结合业务变更记录,当天下午某部门发布了一个参数调整,svn版本历史里正好包括这个模块的配置变更,时间轴完全吻合。再追一下命令细节,发现该进程内部启动了一个数据全量导出任务。原本的增量同步逻辑被一次全量数据变更触发,导致数据文件和日志同时大量写盘。这就是故障的完整链路。4.5 处置措施与最终验证定位到具体进程后,我的处置方案分三步走:第一,用 ionice 将同步任务的I/O优先级调低,避免它和主业务争抢磁盘带宽。比如给该进程设置了 idle 级别,让它只在磁盘空闲时执行读写。要注意的是 ionice 的生效依赖进程所属的I/O调度器支持,CentOS 7 等系统的默认调度器同时支持最佳尝试和限制类型,使用前先确认当前调度器类型:cat /sys/block/sdb/queue/scheduler第二,和业务方确认该全量导出任务能否放到业务低峰期执行。经过沟通,运维侧把任务启动时间调整到凌晨2点,避开晚间的主业务高峰。第三,持续观察一段时间。切换后的第一个完整周期里,再次用 iostat -x 监控 sdb,%util 已从99.8%降到35%以下,wai 也回落到了5%以内,应用响应时间恢复正常。这次排查从头到尾用的就是 dstat 看全局、iostat 看设备、iotop 找进程三层套路,排查时间压缩在20分钟以内。如果一开始就只盯着 iostat 盲目分析,不知道第二层还应该往进程层深挖,恐怕还要折腾大半天。5. 高频故障与避坑要点速查5.1 常见误判场景汇总根据我多年处理系统性能问题的经验,把最常见的问题、容易误判的原因和对应的正确思路整理成一张速查表:现象常见误判正确排查思路%util 长期100%磁盘一定挂了结合 svctm、await、avgqu-sz 判断是否真的队列饱和,SSD场景尤其要谨慎await 高磁盘硬件差先区分是排队时间高还是服务时间高,await 减去 svctm 大致就是排队时间SWAPIN 高磁盘I/O瓶颈优先查内存容量和进程内存占用,可能是频繁换页导致,并不是磁盘本身慢dstat 显示 dsk 高但 iotop 无异常工具统计口径不一致确认是否非进程直接写盘,比如文件系统缓存回写、内部线程刷新,用 iotop -a 看累计量定时任务导致偶发I/O尖峰难以复现,不了了之用 iotop -b 和 dstat 同时采样并导日志,等下次任务触发时归档分析5.2 排查过程中容易被忽略的细节有些细节,平时不遇到根本不会想到,等遇到了发现已经绕了弯路。我挑几个亲历过的点分享一下。第一,采样间隔和采样次数设置不合理,会导致结果失真。iostat 默认不带间隔参数时只输出一次自启动以来的平均数据,这对于定位当前实时问题基本没用。至少设置 1 秒间隔,连续采集5到10次,才能捕捉到当前的波动状态。dstat 和 iotop 也一样,间隔太短比如0.1秒,输出反而会被高频刷新刷得眼花缭乱,建议最少1秒。第二,工具本身的权限限制。iotop 在非root用户下直接运行,会提示无法获取内核数据,输出不完整。如果你习惯用普通用户排查,记得先 sudo。iostat 的扩展模式部分数据也需要特权,生产环境请提前和运维确认好个人账号的提权方式,别等故障发生了现场抓瞎。第三,文件系统缓存(page cache)对数据的影响。Linux 会尽量把读请求缓存在内存中,读操作很多情况下根本不会到达磁盘设备。因此你看到磁盘读很高时,先想想是否有进程绕过了缓存直接读盘,比如使用了 O_DIRECT 的数据库文件读取,这时候 iostat 显示的 r/s 才是真实的物理读。第四,工具版本差异可能导致字段含义不完全一致。比如 dstat 高版本对网络字段的展示方式有调整,老版本里 net/total 显示的是流量总量,新版本某些发行版的包管理定义为流量速率。遇到输出对不上的情况,先执行命令确认当前版本,再下结论。第五,生产环境千万谨慎使用 ionice 直接调整PID的I/O优先级,尤其不要远程操作后立刻断开会话,因为如果调度器不支持相应优先级或业务脚本自身修改了优先级,结果可能和你预期相反。建议先在测试环境验证规则,再在生产执行,执行后至少观察一轮业务周期。5.3 三个工具的配合套路与我的个人习惯如果你完整读到了这里,说明你对这套排查工具是真的感兴趣。我再分享一套我自己用得特别顺手的配合套路。接到性能类问题工单后,我习惯用两步走定位策略:先用 dstat 快速扫描全局资源,把瓶颈维度锁定到磁盘I/O;然后用 iostat -x 和 iotop 双管齐下,一个看设备数据、一个看进程行为,两边对照。iostat 说“磁盘忙”,iotop 说“是哪个进程让它忙”,两者交叉验证,结论基本不会跑偏。如果是周期性故障,比如业务方反馈每天某个时间段都会卡顿,我反而不会实时蹲守。我会在计划任务里县前预置一段采集脚本,把 dstat 和 iotop 的日志自动记录到文件,第二天直接分析故障窗口期的数据。这种“先埋点,后复盘”的方式,在非实时场景下比手工执行命令高效得多。还有一点是不要过早下结论。我看过很多人用 iostat 看到 %util 高就立刻判定“磁盘性能不足”,然后开始提硬件扩容工单。建议一定要结合后续的 iotop 检查,因为有些时候是某个进程发起的低效随机读写导致,真实业务量根本不高。换硬件是成本最高的手段,应该放在所有优化手段之后。排查性能问题,本质上是一次循证的过程。三个命令的合理组合使用,配合冷静的逐步拆解,绝大多数磁盘I/O故障都能在半小时内定位成因。工具始终只是工具,真正值钱的是面对指标时脑中那条清晰的排查链路。