服务器 CPU 占用率不到 20%load average 却飙到 8 以上敲命令一卡一卡——这种故障我排过不止一次后面发现最顺手的工具从来不是什么监控平台而是一条小小的 iotop 命令。它做的事情说穿了就一件实时把磁盘 I/O 摊到每个进程头顶上告诉你到底是谁在读写、写得多猛、等了多长时间。这篇文章我会结合自己实际排障的经历把 iotop 的安装、界面、参数、坑和组合用法讲透。适合刚入门 Linux 的读者也适合日常要跟服务器打交道的运维、DBA 和开发。看完你至少能回答三个问题iotop 怎么装、界面每一列怎么看、以及拿到一份 iotop 日志怎么定位问题。1. 从一次负载飙升说起为什么 top 抓不到真凶1.1 那台让我印象深刻的从库有段时间我负责维护一套数据同步环境其中一台从库专门给报表业务做查询。某天下午业务侧开始报慢查询而且不是一两条是几分钟内几十条。我登上去一看CPU 总使用率不到 20%内存也没满但系统响应明显迟钝top里能看到每个 CPU 核的wa都挂在高位。wa这个参数全称是 I/O wait说人话就是 CPU 闲着等磁盘干活的时间占比。当时wa已经接近 70%说明 CPU 不是没事干而是所有任务都被磁盘卡住了。可问题来了——top能告诉我哪个进程占 CPU 高却没法告诉我哪个进程在疯狂读写磁盘。我盯着进程列表看了十几分钟靠猜才锁定一个大方向最后还是装工具才确认的真凶。那次经历让我明白一件事排查系统卡但 CPU 不高的场景光靠top是不够的必须有进程级别的 I/O 视角。1.2 top 的盲区为什么 load average 飙升而 CPU 不高很多人对 load average 有个误区以为它纯粹反映 CPU 负载。实际内核在统计负载时会把处于不可中断睡眠状态D 状态的任务也计入队列。D 状态最常见的场景就是进程在等待磁盘 I/O 完成比如读数据读了一半磁盘迟迟没响应进程就卡在内核里既不能被杀掉也不占 CPU。所以你会看到这种诡异的组合CPU 使用率不高load average 却很高。不是机器闲着而是大量任务都在排队等磁盘。top里确实也能看到 D 状态进程但仅凭 D 状态你只能知道它在等 I/O不知道它每秒读多少、写多少、等了多久、优先级是多少。想拿到这些信息就需要一个能逐进程展示磁盘吞吐的工具这就是 iotop 存在的意义。1.3 iotop 解决的核心问题把磁盘账本摊到每个进程iotop 的思路和top非常像区别在于它盯的是 I/O 而不是 CPU。它通过读取内核里每个线程/进程的 I/O 统计信息计算出采样间隔内的磁盘读速率、写速率、I/O 等待时间占比然后按你指定的列排序展示。我现在的习惯是只要系统出现CPU 不高、load 高、wa高这三件套直接敲sudo iotop一分钟内就能看到谁在读写磁盘。数据库全量备份、日志轮转、临时文件清理、被入侵进程在挖矿写盘……这些场景我都用 iotop 抓到过。它不能直接告诉你怎么解决问题但能让你在最短时间内找到嫌疑人后续处理就有明确方向了。2. 安装与基础操作比想象中更需要注意的两个细节2.1 不同发行版的安装方式iotop 在主流发行版里都有现成包安装本身不难但有几个发行版稍微有个坑。Debian/Ubuntu 系最简单sudo apt-get update sudo apt-get install -y iotopRHEL/CentOS 7 需要先确认有没有启用 EPEL 源因为默认源里并不包含 iotopsudo yum install -y epel-release sudo yum install -y iotopCentOS Stream 8/9、Rocky Linux、AlmaLinux 这些新一点的版本AppStream 源里一般直接就有试一下sudo dnf install -y iotop就行。Fedora 上也是sudo dnf install -y iotop。SUSE 系用sudo zypper install iotop。装完先确认版本sudo iotop --version我最早用的时候还是 0.6 版本现在很多仓库里已经到 1.x 了。不同版本参数基本兼容但-a累计模式在旧版本上支持得不好如果你用的是老系统建议以实际iotop --help输出为准。2.2 权限问题为什么有些进程显示 0这是新手最容易踩的坑明明装好了执行iotop也能出界面但大部分进程的 DISK READ 和 DISK WRITE 都是 0USER 列也显示不全甚至提示权限不足。不用怀疑就是没加 sudo。iotop 需要读取所有进程的/proc/pid/io统计信息而内核出于安全考虑普通用户只能看到属于自己的进程数据。你可能会想我平时跑top也不用 root 啊但top读的是全局 CPU 统计跟进程级 I/O 统计的权限要求完全不是一回事。正确姿势是sudo iotop如果你是 sudoers 里的用户直接sudo就行。有些场景下服务器禁用了 root 远程登录但 sudo 权限还在用 sudo 同样能拿到全部数据。这一步做对了界面上的数据才会真实可信。2.3 交互界面按键三秒上手启动sudo iotop之后界面风格跟top很接近也是几行总览加一个动态进程列表。交互按键其实就那么几个不需要背手册记住这几个高频操作就够用了按键作用左右方向键切换排序列默认按 IO 排序可以切到 DISK READ 等r反向排序o只显示有 I/O 行为的进程再按一次恢复全部p在进程视图和线程视图之间切换a开启/关闭累计模式q退出我一开始总是忘记o这个键导致界面上刷出来一大堆 I/O 为 0 的进程看得很累。后来养成习惯上来先按一下o只看有读写动作的进程排障效率高很多。3. 界面字段解析DISK READ 和 IO 到底差在哪3.1 顶部总览和五列核心指标iotop 界面顶部有两行总览内容大概是这样的Total DISK READ: 3.2 M/s | Total DISK WRITE: 45.6 M/s Current DISK READ: 3.2 M/s | Current DISK WRITE: 45.6 M/sTotal 开头的是从 iotop 启动到现在的累计口径Current 开头的是最近一个刷新周期内的瞬时值。我排障时主要看 Current因为现在卡不卡取决于瞬时值而不是几分钟前的平均值。进程列表里常见的列有这几项列名含义排障时怎么看TID线程 ID按 p 切换后显示 PID定位具体线程/进程PRIOI/O 优先级类似 be/4 这种格式不合理的优先级会影响调度USER进程发起用户快速区分业务进程和系统进程DISK READ该进程在采样周期内的磁盘读吞吐谁在读盘DISK WRITE该进程在采样周期内的磁盘写吞吐谁在写盘SWAPIN进程等待 swap 换入的时间占比内存压力相关IO进程等待块设备 I/O 完成的时间占比谁在等磁盘COMMAND进程命令行确认身份默认情况下iotop 会把读写速率自动转换为 B、K、M、G 等单位不用手动换算。如果你希望固定用 KB 显示启动时加-k参数就行。3.2 SWAPIN 与 IO谁在等内存谁在等磁盘这两列长的像但代表的问题完全不同。我用一个生活化的类比解释一下。SWAPIN 高相当于一个员工为了省工位把笔记本存在了仓库每次要看笔记就得跑去仓库拿一来一回全耗在路上了。放到系统里就是进程的内存页被换到了 swap进程需要用到这块数据时得先从 swap 读回内存这个等待过程就是 SWAPIN。SWAPIN 高通常说明内存不够用系统正在频繁换页这时候优先排查内存泄漏、降低 swapiness、加内存。IO 高相当于员工明明把资料都摆桌上了但要去打印机取东西结果打印机前面排了几十人的长队。放到系统里就是进程发起了磁盘读写但块设备服务不过来进程只能在内核里等。IO 高才说明磁盘本身是瓶颈常见原因是磁盘性能不足、并发读写太大、或者遇到了 I/O 风暴。两者同时高的情况也不少见。内存不足导致系统开始 swap而 swap 本身也要读写磁盘结果内存压力和磁盘压力互相叠加这时你会看到一票进程 SWAPIN 和 IO 都很高。3.3 盯盘顺序先看瞬时读写再看等待占比拿到 iotop 界面我的习惯是先按o过滤出活跃进程然后看 DISK READ 和 DISK WRITE 两列把读写量最大的几个进程圈出来接着再看对应进程的 IO确认它是不是真的在等磁盘。有人只看 DISK READ 大就认定是罪魁祸首其实不够严谨。一个进程读盘量很大但如果用的是异步 I/O 或者磁盘响应很快IO 可能并不高对系统整体影响也有限。反过来有的进程每秒只读写几十 KB但 IO 一直卡在 80% 以上说明它在频繁发起小 I/O每次都要等很久这种照样能把系统拖垮。所以我的判断标准是读写量大且 IO 高基本实锤读写量不大但 IO 高需要结合进程行为进一步判断可能是频繁随机小 I/O也可能是进程本身在 awk 等待某些特殊状态。4. 命令行参数把 iotop 变成一台自动化采集工具4.1 高频参数组合速查交互模式适合人工排查但如果你想记录现场、落到日志、或者丢给脚本处理就必须用批处理模式。iotop 的命令行参数不算多高频的几个我整理成了一张表参数作用-o只显示有 I/O 行为的进程/线程-b批处理模式结果按行输出适合重定向到文件-n 次数采样多少次后退出配合 -b 使用-d 秒数刷新间隔默认 1 秒-k以 KB 为单位显示-t每行输出前加时间戳-a累计模式显示进程累计 I/O 量-P只显示进程不展开线程-u 用户名只看指定用户举个例子我想抓 2 分钟现场每 2 秒采样一次只记录有 I/O 的进程顺便带上时间戳可以这样写sudo iotop -b -n 60 -d 2 -o -k -t /tmp/iotop_$(date %F_%H%M%S).log这里的-n 60配合-d 2正好 2 分钟。注意批处理模式下即使你不加-o它也会把所有进程都打印一遍日志会非常长加-o之后只输出活跃项日志短很多也更容易读。4.2 批处理模式下的现场抓取有些故障是偶发的你不可能一直盯着屏幕。我常用的思路是接到告警后不急着上服务器人工看而是先启动一个短时的 iotop 采集任务把现场留存下来然后再慢慢分析。假设你现在收到告警说磁盘 I/O 异常想抓 5 分钟的数据可以执行sudo timeout 300 iotop -b -o -k -t /tmp/iotop_5min.log 21用timeout包一层比手动算-n次数更稳妥。即使采样次数因为系统卡顿没跑满300 秒后也会自动结束不会出现一个采集脚本永远挂着没人管的情况。采集完成后直接查看日志head -50 /tmp/iotop_5min.log sort -t| -k3 -rn /tmp/iotop_5min.log | head -20我一般在日志里找 DISK READ 和 DISK WRITE 数值最大的那几行然后反查时间戳看异常窗口对应的进程名。如果日志里出现了某个平时不常见的命令路径比如临时目录下被上传的执行文件那就要小心是不是有异常程序在写盘。4.3 累计模式找出闷头写盘的进程排查实时问题时瞬时速率最直观但有一些场景需要看累计值比如某个进程从开机到现在到底写掉了多少数据。这时候用-a参数sudo iotop -a -P -k加了-a之后DISK READ 和 DISK WRITE 两列不再显示每秒速率而是显示进程启动以来的累计 I/O 量。你可以按累计写排序找出谁才是真正的写盘大户。这个方法特别适合定位那种间歇性写盘、瞬时速率不高但总量很大的进程。比如某些日志组件平时每秒只写几十 KB 看似正常但按累计模式一看占了几十 GB 磁盘空间还在不停涨那就要注意磁盘是不是快被写满了。-P参数建议一起加上因为按进程看比按线程看更直观。5. 排障实战一次备份任务引发的磁盘 I/O 风暴5.1 现象与第一轮排查回到最开始那台从库。当时我先跑了一轮常规检查top看到 load average 8.xCPU us 不到 15%wa 接近 70%free -h显示内存有富余swap 使用量不大dmesg -T | tail没有硬件报错iostat -x 1看到所在块设备 %util 接近 100%await 非常高到这里基本可以定性磁盘 I/O 就是瓶颈。但 iostat 只能看到设备维度的数据无法告诉我具体是哪个进程在读写。于是我把 iotop 请出来了。5.2 iotop 抓现场的过程我执行的是sudo iotop -b -n 10 -d 1 -o -k -t用批处理模式抓 10 次快照每次间隔 1 秒只显示有 I/O 的进程。前几行输出很快锁定了一个可疑对象一个名字很长的 mysqldump 相关进程DISK READ 稳定在 150MB/s 左右DISK WRITE 也有几十 MB/sIO 接近 90%。当时我有点意外因为按照调度全量备份任务应该在凌晨执行现在明明是下午业务高峰期。看了日志里的时间戳确认备份进程是在当前时间点刚刚拉起来的这说明调度系统出问题了——要么定时任务配置写错要么触发条件被意外满足。5.3 定位、止损与 ionice 的取舍确认是备份进程后我面临一个选择直接杀掉还是先降优先级让它慢慢跑当时的业务影响已经很严重慢查询大量堆积我选择先止损把异常时间窗口内的备份进程停掉。执行前我仔细确认了进程 PID 和命令行参数避免误杀主库上的同名进程。用kill或pkill -f都可以但pkill -f一定要写全路径特征防止误伤。如果场景允许备份任务继续跑只是不希望它抢占业务 I/O可以用 ionice 调整优先级sudo ionice -c 2 -n 7 -p PID sudo renice -n 19 -p PID-c 2表示 best effort 调度类别-n 7是这一类里的最低优先级renice -n 19把 CPU 优先级也降到最低。但要注意一点ionice 的效果取决于块设备使用的 I/O 调度器CFQ 这类调度器下效果比较明显而现代 SSD 上常见的 none 调度器基本不做优先级排队这时 ionice 的作用非常有限。这也是一个很多人容易忽略的坑——不要以为调了 ionice 就万事大吉先确认一下系统中的调度器策略cat /sys/block/sda/queue/scheduler如果显示none就得改用其他手段限制 I/O比如限流、错峰、或者从业务层面降低并发。5.4 复盘让工具帮你把为什么也查出来杀掉异常备份进程后load average 在几分钟内明显回落慢查询也逐步恢复。但问题没有结束我得搞清楚为什么备份任务会在这个时间点被拉起来。查了任务调度配置后发现是时区配置和调度表达式叠加的问题导致触发时间比预期提前了几个小时。这个根因跟 iotop 无关但如果没有 iotop 快速锁定备份进程排查方向可能会歪到数据库性能、网络延迟上去浪费大量时间。经历这次之后我给备份任务脚本加了几层保护启动前检测当前负载负载过高直接延迟启动时用 ionice 和 nice 降低优先级运行期间定时采样 iotop 数据上传到监控系统设置阈值告警。现在这些机制已经成为我处理所有后台任务的默认配置。6. 到这里还没结束iotop 的局限与组合工具6.1 与 iostat、pidstat 的分工排障不能只靠一个工具不同维度需要不同工具配合。常用组合是工具维度典型用途topCPU、内存、负载第一眼发现异常iostat -x块设备维度确认磁盘是否瓶颈iotop进程/线程维度定位具体进程pidstat -d进程维度历史记录采集历史 I/O 数据我的一般流程是先看 top 和 load发现可疑再跑 iostat 确认磁盘压力然后上 iotop 锁定进程如果需要对比历史趋势用 pidstat 记录一段时间pidstat -d 1 60 /tmp/pidstat_io.logpidstat 的输出比 iotop 更容易做趋势分析因为它能按固定格式持续输出适合丢给监控平台。iotop 则胜在实时交互和线程级细节两者互补。6.2 数据来源与几个容易误判的点iotop 的数据来自内核中进程的 I/O 统计也就是/proc/pid/io。这个文件里记录了进程累计读写的字符数、实际从磁盘读取的字节数、实际写入磁盘的字节数等字段。iotop 通过两次采样之间的差值计算出每秒速率。这里有一个非常重要的细节read_bytes统计的是真正从块设备读到的数据页缓存命中的读操作是不会计入的。换句话说一个进程如果用 mmap 反复读取同一份大文件第一次读完后数据进了页缓存后续再读就不会体现在 DISK READ 上。所以判断进程是否真的在读盘不能只看 DISK READ 大小还要结合 IO。IO 高说明进程确实在等磁盘响应这个信号比单纯的吞吐数字更可靠。另外一个容易误判的点是O_DIRECT 或者异步 I/O 场景下读写会绕过页缓存直接访问块设备磁碟统计可能比你预期的更高。这属于正常现象不代表系统异常。6.3 容器和网络文件系统场景现在的生产环境大量使用容器iotop 在这种场景下有一个明显的边界它看的是宿主机视角的进程统计。如果你在容器里执行 iotop默认只能看到该容器 namespace 内的进程而且数据在部分内核版本上会不完整。想监控容器内进程的 I/O更好用的方式是回到宿主机上用 iotop 过滤容器对应进程的 PID或者使用 cgroup 层级的 I/O 统计配合监控平台查看整个容器的读写总量。不要试图把 iotop 装进每个容器里维护成本高数据还不一定准。网络文件系统NFS、CIFS挂载的目录也有类似问题。客户端进程的读写请求会体现在 iotop 里但它无法告诉你底层网络存储的性能瓶颈在哪。这时候你需要看的是网络延迟、服务端监控、以及挂载参数里有没有影响性能的选项iotop 只能提供客户端侧的信息。6.4 组合拳与最后一点实操心得我最后分享一个自己长期在用的习惯。排查结束后我不会让 iotop 常驻运行因为它的采样和刷新本身有开销日志也会膨胀。更稳妥的做法是把它当做急诊工具接到告警后快速抓取几分钟快照分析完就停掉。如果需要持续监控让 pidstat 或监控平台去干这个活。另外一个经验是顺序比工具更重要。先把是不是磁盘问题确认清楚再决定要不要上 iotop。上来就装工具、抓一堆日志反而容易被噪声淹没。iotop 解决的是谁在读写磁盘但磁盘是不是瓶颈这个问题iostat 和 load average 就能回答。最后送一句话遇到系统卡但 CPU 不高的情况别急着怀疑业务代码先敲一下sudo iotop很多时候真凶就在前五行里。