尧图精选

iopp工具实战:Linux磁盘高负载下如何按进程定位IO元凶

🕒 发布时间:2026/9/15 7:36:10 📁 来源:尧图网络
先从一个最常见的排障场景说起你盯着监控大屏发现某台服务器的磁盘util已经冲到90%以上iowait居高不下。你本能地敲下top结果CPU、内存全都很正常没有任何进程吃掉大量CPU。这时候最尴尬的事情出现了——你知道磁盘在忙却不知道是谁在折腾磁盘。如果你也遇到过这种“磁盘高负载却找不到元凶”的困境iopp就是一个值得装进工具箱的小工具。它是一个专门按进程维度查看IO占用的小程序定位思路非常直接像top一样刷新把每个进程的实际磁盘读写情况列出来谁在疯狂读写、谁的IO占比高一眼就能看到。这篇文章我会从工具原理、安装方式、使用细节到一次完整排查案例把我实际用下来的经验全部写出来方便你遇到同样问题时直接抄作业。1. 先分清iostat看的是磁盘iopp看的是进程1.1 top帮不了你的原因很多人习惯用top解决一切但top默认只展示CPU、内存和负载并不能直接告诉你某个进程产生了多少磁盘IO。即使你按x切换到排序模式也找不到一个“IO排序”按钮因为top的数据模型里根本没有按进程统计磁盘读写的字段。这时候常用的替代方案是iostat。它能告诉你一整块磁盘的吞吐、IOPS、%util但它是系统级视角不会拆解到进程。你可以知道“这块盘快被写穿了”但不知道是数据库在刷脏页、日志采集在落盘、还是一个失控的脚本在死循环写文件。要回答“谁在写”必须靠按进程维度统计IO的工具。iopp做的事情就是读取Linux内核暴露在/proc文件系统里的每进程IO统计信息然后按自己的采样逻辑计算出一段时间内每个进程的IO变化量再以类似top的交互界面展示出来。它不依赖复杂的监控平台不需要装agent也没有守护进程核心逻辑就是“读/proc、算差值、刷界面”。1.2 和iotop、pidstat放一起怎么选按进程看IO市面上还有两个常见选择iotop和pidstat来自sysstat包。很多人会问既然有iotop了为什么还要用iopp我个人的判断是这样的工具数据来源是否需要root界面形态突出场景iopp/proc/pid/io建议root否则只能看自己的进程类似top实时刷新轻量、老机器、无额外依赖快速定位高IO进程iotop/proc/pid/io必须root全屏交互带动态排序界面丰富能看线程和累计值适合长期观察pidstat -d内核IO统计普通用户可用但受限滚动输出不做全屏适合脚本和日志采集便于保存历史三者看的数据源其实是同一个/proc/pid/io。区别在于展示粒度和额外依赖。iotop功能确实更强但有几个现实问题它需要root权限在某些加固过的生产环境里你未必敢随意提权另外iotop需要在系统里安装Python或者依赖脚本依赖更多。pidstat的问题是它是“滚动打点”式的输出每次刷一行时间戳不直观而且默认也不显示累计IO百分比需要额外加参数。iopp的优势恰好是“轻”。一个C语言小程序编译完就一个二进制文件拷贝到/usr/local/bin就能用。在内核2.6.20以上的Linux系统里基本不用愁兼容性。对于“就想快速看一眼到底哪个进程在读写磁盘”这种场景它比iotop来得干脆。2. 装好iopp的几种靠谱办法2.1 先从包管理器里找不同发行版对iopp的支持不一样。我平时接触的机器以Ubuntu、Debian、CentOS为主做法是先在包管理器里搜一遍能直接装就省事# Debian / Ubuntu apt-cache search iopp # CentOS / RHEL / Fedora yum search iopp如果包管理器里能直接搜到直接apt install iopp或yum install iopp即可。但说实话这个工具比较小众很多官方源里没有尤其是CentOS 7这种老系统默认源基本找不到。遇到这种情况别浪费时间折腾源直接走源码编译。2.2 源码编译老机器也不慌iopp的源码很短依赖也很少编译过程非常传统。你可以在GitHub或老牌开源代码托管站上搜索iopp源码下载后执行wget 下载地址/iopp.tar.gz tar -zxvf iopp.tar.gz cd iopp makemake之后目录下会生成一个iopp可执行文件把它放到/usr/local/bin即可全局使用sudo cp iopp /usr/local/bin/如果你在编译时遇到找不到curses.h或ncurses.h的报错说明系统缺少ncurses开发头文件这是最常遇到的依赖问题。Debian/Ubuntu装libncurses5-devCentOS/RHEL装ncurses-devel补上再make就行。# Debian / Ubuntu sudo apt install libncurses5-dev # CentOS / RHEL sudo yum install ncurses-devel我在一台很老的CentOS 6机器上也编译过源码本身不挑编译器gcc版本旧一点也没问题。这算是这个工具一个很讨喜的特点在缺少新工具链的环境里它依然能跑起来。2.3 装完后的自检清单装完先别急着用花十秒钟确认环境是否正常。第一步执行iopp -h或iopp --help看版本有没有正常输出。不同版本的参数名会有差异以你机器上实际帮助信息为准。第二步检查/proc/pid/io文件是否存在且可读。这个过程很重要因为iopp的数据来源就是这个文件。你可以随便找一个进程测试cat /proc/1/io正常会输出rchar、wchar、syscr、syscw、read_bytes、write_bytes、cancelled_write_bytes这些字段。如果提示权限不足说明当前用户没权限读其他进程的IO信息需要用root运行iopp。3. 把iopp用明白命令行操作和读界面3.1 最常用的启动组合我实际用的最多的命令是下面这两个# 显示所有进程的IO情况 sudo iopp -a # 只看某个进程 sudo iopp -p PID为什么加-a因为默认情况下iopp的表现更像一个“只看自己”的小工具加上-a才会列出系统里所有进程。在生产环境排查时你根本不知道目标进程是谁所以一定先用-a看全量。如果你希望刷新速度慢一点方便截图和记录可以用watch包一层sudo watch -n 1 iopp -a这里要提醒一句iopp本身的界面是带刷新逻辑的套watch只是让它变成“每1秒输出一屏”的效果适合录屏或者给人演示。真正要留存数据时建议用后面的批处理方式。3.2 界面/输出字段到底看什么由于iopp不同版本界面存在差异我这边以我常用版本为例输出大概长这样PID USER NAME IO% READ_BYTES WRITE_BYTES 4123 mysql mysqld 43.2 234881024 10485760 517 root kjournald 12.5 0 52428800 7788 admin python3 8.1 1048576 41943040不同版本列名可能有区别但核心信息就那么几项进程PID、用户名、进程名、IO占比、读字节数、写字节数。你不需要背字段只需要记住三个判断逻辑IO%高的进程就是“此刻最折腾磁盘”的进程。READ_BYTES高说明在读文件或读磁盘数据。WRITE_BYTES高说明在写文件、刷日志或者落盘。这里有一个容易误读的点READ_BYTES和WRITE_BYTES在不同版本里可能是累计值也可能是本周期增量。如果是累计值你要看的是它是否在持续增长如果是增量直接看数值大小。为了避免误判我通常在观察时连续看两三次只要某个进程的数值一直在涨基本就是它没跑了。3.3 几个能提高效率的顺手姿势iopp在使用上还有几个小技巧是我踩过坑之后整理出来的。第一个是“先iostat确认再iopp定位”。不要一上来就开iopp盯着看先跑一下iostat -x 1确认系统确实存在IO瓶颈再打开iopp -a。否则一堆进程里会有很多瞬时波动容易干扰判断。第二个是配合grep快速过滤。如果怀疑是Java进程可以这么看sudo iopp -a | grep java虽然这样会失去实时刷新效果但能快速拿到“Java进程当前IO数据”的快照适合脚本和远程排查。第三个是使用批处理模式。在部分版本中iopp支持-b参数输出不会刷新光标而是像普通命令一样逐行打印。这个模式适合把输出重定向到文件sudo iopp -a -b /tmp/iopp_$(date %F).log如果版本不支持-b也可以直接配合script命令录制终端或者用后面的自采集脚本替代。反正目标是拿到数据工具细节不用死磕。4. 一次真实排查磁盘告警到进程落网的完整过程4.1 现场现象和第一轮验证我之前处理过一台数据库备份服务器的IO问题情况和开头描述的场景几乎一样。凌晨2点开始磁盘%util持续100%iowait一路飘红但业务侧并没有大查询。我登录服务器后先执行了top结果进程列表里的CPU占用都很低完全看不出异常。接着用iostat -x 1观察发现vdb这块数据盘的写吞吐特别大每秒写几十MB明显是某个后台任务在大量落盘。可问题是前台没有跑任何大任务备份脚本也还没有到调度时间。这时候我就打开了iopp。4.2 iopp锁定嫌疑进程执行sudo iopp -a后等了大约两三秒界面开始刷新。第一眼看到的是mysqld的IO%确实不低但真正让我注意的是下面一个名为gzip的进程它的WRITE_BYTES在持续快速上涨IO%一度冲到30%以上。当时系统里有多个gzip进程还以为是巧合。用ps -ef | grep gzip一查发现是某个日志切割脚本在压缩前一天的MySQL binlog。脚本通过cron启动本意是把binlog压缩后保留7天但压缩文件的输出路径没做规范化直接写在了数据盘上导致凌晨压缩任务和数据库刷脏页撞在一起把磁盘IO顶满了。这一步就是iopp最典型的用法不是分析“所有进程的IO总和”而是找出“哪个进程的IO在飞快增长”。数值绝对值高不一定有问题持续增长才是实锤。4.3 用/proc、lsof、strace把证据链补完锁定PID之后我习惯再补两刀防止误杀。第一刀是看这个进程打开了哪些文件ls -l /proc/PID/fd这一步能看到gzip进程的文件描述符指向哪里。当时看到里面有一个binlog.000012.gz.tmp就基本确定它正在压缩哪个文件了。第二刀是用strace或lsof确认写路径。如果环境允许可以用strace短时间跟踪写操作sudo strace -p PID -e tracewrite -c跑几秒后按CtrlC会统计出这个进程写系统调用的次数和数据量。如果写调用的数量明显异常那根因就非常清楚了。到这里其实已经不需要继续证明什么直接处理就行。4.4 处理动作与结果复盘当时我的处理动作分两步第一步给正在运行的gzip进程设置IO优先级让它别跟数据库抢带宽sudo ionice -c2 -n7 -p PID这个操作让压缩任务变成“只有磁盘空闲时才写”数据库的IO压力明显下降。第二步修改日志切割脚本把压缩输出目录从数据盘改到独立的备份盘并加上ionice参数。改完之后第二天的备份窗口没有再出现%util持续100%的情况。回过头复盘这个问题的核心不是gzip本身而是“压缩任务没有做IO隔离”。如果用top查几天都发现不了因为gzip的CPU占用只有几个百分点但用iopp看瞬间就暴露了。所以我的建议是任何跑批任务较多的服务器都应该在排障流程里加入“进程IO检查”这一步工具不需要复杂能快速锁定进程就够。5. 实战中绕不开的坑和进阶玩法5.1 看着很低但磁盘很忙先检查这两类情况用iopp的时候最怕是“磁盘利用率很高但iopp列表里没有明显高IO进程”。这种情况并不代表工具失效而是IO可能不在常规进程维度上。第一类情况是内核线程在刷盘。比如flush-253:0、kworker这类内核任务它们负责把page cache里的脏页写回磁盘/proc/pid/io里不一定能很好地体现真实块设备IO。遇到这种情况我习惯用atop的磁盘域或者perf进一步看内核栈单纯靠iopp确实不够。第二类情况是文件已经被进程关闭但页缓存还没落盘。进程写入数据后退出数据留在内存page cache里由pdflush或flush内核线程后续写回磁盘。这时候从进程维度看IO已经归零但磁盘还在写。简单说iopp看的是“进程发起的IO”而磁盘上实际发生的IO还包含“内核代写”的部分。如果你遇到IO高但找不到进程的场景检查顺序建议是先看iostat确认是读还是写再用iopp和ps -eLf看用户进程最后用cat /proc/meminfo看看Dirty字段是不是很大。如果Dirty持续堆积那多半是刷脏页导致的处理思路是调低vm.dirty_ratio或vm.dirty_background_ratio让脏页更早、更均匀地落盘。5.2 权限、容器、内核版本的边界iopp这工具虽然好用但有几个边界你必须心里有数。权限边界很容易踩。普通用户运行iopp大概率只能看到自己启动的进程因为/proc/pid/io默认只有进程属主和root可读。所以我在生产环境会先看一下当前用户是不是root不是就加上sudo。有些团队会使用普通用户加CAP_SYS_ADMIN权限的方式可以生效但没必要为了一个小工具去动权限模型直接用root更省事。容器环境是另一个坑。在容器里执行iopp默认看到的是容器命名空间内的进程很多宿主机的IO尤其是文件系统和块设备层并不会完整映射到容器内的/proc。如果你在Docker容器里发现iopp输出一片空白别以为是工具坏了先退回宿主机观察。内核版本方面iopp依赖的每进程IO统计是内核2.6.20才加入的。现在基本不会再碰到低于这个版本的系统但如果你维护的是极老的嵌入式环境还是要先验证一下/proc/pid/io是否存在。5.3 不装额外工具用/proc/pid/io自己采样有些环境比我想象中还要严苛连编译一个新二进制都不允许。这时候可以完全抛弃iopp直接用/proc/pid/io手动采样。思路很简单连续读两次目标进程的write_bytes或read_bytes差值除以间隔时间就是平均速率。我写过一个非常简短的脚本用来后台监控某个关键进程的写速率#!/bin/bash PID$1 INTERVAL${2:-5} r1$(awk /write_bytes/{print $2} /proc/$PID/io) sleep $INTERVAL r2$(awk /write_bytes/{print $2} /proc/$PID/io) echo write rate: $(( (r2 - r1) / INTERVAL )) bytes/s这个脚本看起来朴素但在生产环境里很实用。你可以把它放到cron里每隔一分钟记录一次形成历史曲线。iopp本身不保存历史但这套手工方式可以弥补。如果要做更完整的监控建议先把read_bytes和write_bytes的差值都算出来再结合iostat里的磁盘吞吐做比对。当两者差距很大时说明有大量IO并不是直接由某个用户进程贡献的再往内核刷页、文件系统日志等深层方向排查。我在实际使用中最深的一点体会是iopp这类小工具解决的是“定位嫌疑进程”这一步它没法直接告诉你根本原因但它能让排查过程从几小时缩短到几分钟。排查IO问题时别指望一个命令包打天下把iostat、iopp、lsof、strace、ionice按顺序组合起来用才能在最短时间内把根因按在地上摩擦。希望这篇经验能帮你少走点弯路下次再遇到磁盘告警至少能第一时间想起还有iopp这么个轻量工具能用。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →