通过top、vmstat、free、df、iostat组合定位Linux性能瓶颈 1. 资源查看不是“跑几个命令”那么简单Linux系统资源查看top、vmstat、free、df、iostat这五个命令几乎是每本入门书里的标配。我见过很多人把每个命令背得滚瓜烂熟但一遇到服务器告警还是不知道从哪下手。原因是他们把这些命令当成了“查看工具”而没当成“线索链”。实际上这些命令组合起来就是一套系统性能诊断流程CPU瓶颈看top、vmstat内存瓶颈看free、vmstat磁盘瓶颈看df、iostat。每个命令看到的只是一个切面但切面之间是有联动的。这篇文章适合刚接触Linux、或者已经会敲这几条命令但想更深入理解输出含义的人。我不会只给你讲参数而是分享实际排查中怎么用、怎么解读、怎么从一行数字里找到问题根因。目标很简单让你从“看到命令输出”变成“看懂系统状态”。为什么把这几条命令放一起说因为服务器卡成PPT时你不可能只靠一条命令就知道原因。比如CPU高到底是用户进程占用还是内核在做IO等待内存看起来吃紧是真的不够还是有大量缓存可以回收磁盘报告满了但du找不到大文件那多半是文件被删但仍被进程占用。这些问题单看top或df都可能被骗需要交叉验证。我尽量把每个命令的“看什么”“忽略什么”讲清楚带上实际数值示例。读完你至少能做到拿到一台故障机器按顺序执行这几条命令几分钟内定位出大致瓶颈方向。当然这套东西熟练之后你会形成自己的排查习惯不一定照搬我的顺序。2. top从进程列表到系统负载的实时监控2.1 第一屏不是进程列表是那五行的“总览”很多人打开top眼睛就直接盯住进程列表找哪个进程CPU高。这没错但容易漏掉更重要的信息。top默认输出前五行的系统概况我已经养成习惯是先看这里再决定要不要看进程表。第一行显示系统当前时间、已运行时间、登录用户数和负载平均值。这里的load average有三个数值分别代表过去1分钟、5分钟、15分钟的平均负载。注意这个负载不是CPU使用率而是处于可运行状态和不可中断睡眠状态的进程平均数量。一个粗略判断标准是如果负载值接近或超过CPU核心数说明系统有排队可能已经过载。但要注意如果是IO等待导致的不可中断进程负载高但CPU可能并不忙。第二行和第三行是进程总数和运行、休眠、停止、僵尸进程数量。我特别关注zombie如果持续有僵尸进程可能是父进程没有正确回收子进程。少量没问题大量就别忽略。第四行、第五行是CPU状态和内存状态CPU的us、sy、ni、id、wa、hi、si、st分别代表用户态、系统态、优先级调整、空闲、IO等待、硬中断、软中断、被偷取时间。us高通常是用户程序运算密集sy高可能是系统调用频繁wa高则说明CPU在等磁盘st高多见于虚拟化环境被宿主机抢占。2.2 交互按键是top的“隐藏效率”进入top界面后千万不要只用键盘上的上下键翻进程。我常用这几个按键P按CPU使用率排序M按内存排序T按累计CPU时间排序。排查问题时P是最常用的能快速看到CPU占用前几名但有时按T也有惊喜——某个进程瞬时CPU不高但累计时间很长说明它是一个持续消耗资源的老大难。数字键1可以展开每个CPU核心的使用情况如果多核系统只有一个核接近100%其他空闲可能是单线程程序或中断绑定不均和整体负载高是两回事。k键可以直接发送信号给进程r键可以调整进程优先级。不过我在生产环境几乎不用这两个键生怕手抖输错PID。我更喜欢退出top后用命令行kill或renice至少多确认一次。2.3 top的局限它只给你一个“瞬间”top默认大约3秒刷新一次进程列表每次变化都很快。就算某个进程平均CPU很高你看到的瞬间值也可能只是50%或突然飙到100%。如果是间歇性消耗top很难抓到规律。所以遇到CPU问题我通常不会只靠top下结论会配合top -bn1和vmstat的多点采样。top -b是批处理模式-n1表示只输出一次。这个输出没有交互界面但内容和交互式的第一屏及进程列表完全一样。脚本或连续采样时很有用比如每隔5秒执行一次top -bn1把结果追加到文件事后分析趋势。还可以用-p指定PID只看某个进程排查单进程资源占用时比全量输出容易读。2.4 如何从top里区分“瞬时高”和“趋势高”实际操作中我会先看load average的15分钟值如果这个值一直往上走说明系统压力在累积不是偶发现象如果只是1分钟高、15分钟很低可能只是刚刚有任务启动。CPU状态里的wa高配合进程列表里D状态的进程基本可以判断是IO瓶颈。进程列表里进程状态为R代表正在运行S代表睡眠D代表不可中断的磁盘等待。如果大量进程处于D状态说明它们都在等IO系统再空转也跑不快。这个逻辑比只盯CPU百分比准确得多。3. vmstat连续采样才能看准CPU、内存、IO趋势3.1 先从命令格式说起vmstat的经典用法是 vmstat 1 5意思是每隔1秒取一次样一共取5次。第一次输出比较特殊它显示的是自开机以来的平均值后续四次才是实时的样本。很多人第一次看时被第一行误导其实应该看后面的行。我习惯执行 vmstat 1 10取10个点能覆盖一个大约9秒的窗口。如果要排查持续性问题可以 vmstat 1 30再配合watch或重定向到文件。输出分六大列procs、memory、swap、io、system、cpu。每一列里有细分字段。不要一股脑全看按当前怀疑的方向挑重点。3.2 procs里的r和b是阻塞的最直接信号procs列下的r表示当前等待运行队列中的进程数b表示处于不可中断睡眠状态的进程数。很多人只关心CPU使用率忽略了r。其实r才是判断CPU是否饱和的核心指标如果r长期大于CPU核心数说明很多线程在排队等待CPU即使us不是100%系统也已经算过载了。b如果持续不为0一般是IO存在问题某进程在等磁盘或网络等外部资源。我记得一次排查某应用性能下降us和sy都不高CPU有大量空闲但是r排队很长应用响应依然慢。后来发现是线程池配置过小任务都堆积在用户态队列里和CPU其实没直接关系。这也说明vmstat的r值要看但还要结合进程内线程状态综合判断。3.3 memory和swapsi/so 不是随便看看memory列有swpd、free、buff、cache。swpd表示已经使用的交换分区大小free是空闲物理内存buff是块设备缓冲cache是页面缓存。很多人以为cache太大就是内存泄漏其实恰恰相反cache是Linux用来加速文件读写的内存越空闲Linux越倾向于把缓存做大。真正需要担心的字段是si和so分别是每秒从swap换入、换出的量。如果so长期大于0说明系统内存真的吃紧正在把页面换出到磁盘如果si也大说明进程又要从swap读回来频繁换页会让整个系统变慢CPU可能有大量sy或wa。有时候free显示swpd为0但si/so有流量因为内核可能在回收页面。大多数时候只要so不为0就要警惕内存压力下一步用free -h看看available是不是已经逼近安全线。3.4 io、system和cpu配合读io列有bi和bo分别是每秒从块设备读入和写入的块数单位是块。这个数字大说明磁盘读写频繁但没法区分是缓存命中还是真实IO所以不能单独拿来判断磁盘性能瓶颈更适合配合iostat看设备队列和等待时间。system列包括每秒中断数in和每秒上下文切换数cs上下文切换高说明系统里进程和线程频繁切换常和线程数量过多、锁竞争或者syscall过多有关。cpu列在前面top里已经讲了一部分vmstat的好处是每个采样点单独输出能看出来us/wa随着时间的变化趋势是平滑升高还是突然尖刺。3.5 怎么用vmstat快速定位瓶颈实战中我会这样用先执行vmstat 1 5看r是否大于CPU核数b是否持续非0如果b高再看wa是否高如果wa高跳过去看iostat如果si/so有值去看free -h如果cs特别高先去分析进程的线程行为。这条判断路径几乎可以应对80%的“服务器突然变慢”问题。vmstat不能告诉你具体是哪个进程造成的但它能帮你锁定方向缩小范围。4. free别再被“buff/cache”绕晕了4.1 默认的free输出很多人看错直接执行free -h输出里第一行是内存总数total、已用used、空闲free、共享shared、buff/cache和available。很多人在意used是不是很高看到free很少就觉得内存快满了。其实used这一项包含了page cache和buffer这些缓存是可回收的不可能按used直接判断内存压力。内核真正关心的是系统还有多少内存可以立即分配给应用程序这个数字就是available。所以第一眼看free时我只看两个数total和available。available是估算出的、在不触发swap的情况下还能分配给进程的内存量。如果available长期低于总内存的10%甚至5%内存才真正紧张。free那列数值低但available还很高完全不用慌。4.2 buff/cache回收机制和手动回收Linux通过page cache缓存文件数据读文件时会命中缓存提升性能。当你看到cache占了大量内存这是正常设计。需要缓存时内核会清理cache来满足新分配需求。大多数情况下不需要手动执行echo 3 /proc/sys/vm/drop_caches去清缓存尤其在生产环境强制清缓存会让文件读写性能暂时变差还可能引发一些意外问题。我见过有人为了“释放内存”定时清缓存结果数据库查询比平时慢了一倍。除非你在做性能基准测试需要统一缓存状态否则别去动它。如果实在想确认内存使用情况可以看/proc/meminfo里的MemAvailable、MemFree、Buffers、Cached、SwapTotal、SwapFree等更细粒度字段。有些命令显示的used减去buff/cache才是真正进程占用但内核角度大家更认可available。4.3 判断内存压力的几个信号内存不足时swap使用缓缓上升是第一个信号。free -h观察swap的used列如果持续增长说明有些内存页被换出。第二个信号是available越来越低同时si/so有值。第三个信号是OOM但OOM是最后关头生产环境最好别等到它出现。如果同时有缓慢的内存增长趋势可能是应用在泄漏可以持续记录free的输出隔一段时间对比或配合进程的RSS变化。RSS查看可以用ps aux --sort-rss取前几或者top按M排序后看RES列。RES是进程驻留内存浪费较大时可以怀疑有泄漏。但注意RES包括共享库和内存映射文件并不等于私有内存。真要精确到进程可以用smem命令如果安装了看PSS/USS。普通排查以available和swap趋势为主就够了。4.4 一个典型的误判场景有个监控脚本每天检查free的used列一旦超过90%就报警。结果这台机器天天报警但实际上应用响应很正常。运维小哥被烦得不行最后发现是Nginx加静态文件缓存把大量磁盘文件读进page cacheused确实很高但available一直很充裕swap完全没动。把监控指标改成available之后报警消失了。这就是free命令最常见的坑希望你别再踩一次。5. df磁盘空间与inode你只看到了一半5.1 常规检查空间使用率和挂载点df -h输出每个文件系统的容量、已用、可用、使用百分比、挂载点。排查空间问题时先找到使用率接近100%的挂载点。但在动手删除文件前一定要确认这个目录下哪些文件占空间最大。这时候组合拳是df定位哪个挂载点满du进入对应目录逐步定位大文件。最快的是du -sh /path/* | sort -rh 取前十或者用du -ahx / 在一堆输出里找大的。注意du扫描整个根目录可能耗时很长生产环境慎用最好先从已知的常见大目录开始比如/var/log、/home、/tmp、/opt。5.2 空间满了但不知道谁占的从文件系统层面排查有个经典故障df显示根分区100%但用du -sh / 把整个根目录加起来发现加起来的使用量远小于df的used值。这种情况大概率是文件被删除了但还有进程保持文件句柄没有释放。删除文件只是删除了目录项如果文件仍被某个进程打开磁盘空间不会立即释放直到进程关闭该文件或进程退出。查看方法是用lsof | grep deleted或者lsof L1直接列出link count为0但仍被打开的文件。找到进程后要么重启进程要么让应用自己关闭句柄。不处理的话空间会一直被占用日志可能一直在增长把新写入彻底堵死。5.3 inode用尽df -h看不出问题文件却创建不了除了block空间文件系统还有inode表每个文件或目录至少一个inode。df默认显示的是数据块的使用率即使数据块还有很多inode耗尽也会导致“No space left on device”错误但df -h看上去正常。检查方法就是df -i看IUse%是否接近100%。inode耗尽常见于大量小文件场景比如邮件队列、临时缓存目录、或者频繁创建小日志文件。遇到inode满只能清理旧文件或者把该目录挂载的文件系统重建为inode更多的文件系统比如xfs的mkfs参数但那是后话。应急时先find /path -xdev -type f找出数量巨大的目录然后清理不需要的文件。5.4 df -T和挂载类型df -T可以额外显示文件系统类型比如ext4、xfs、nfs、tmpfs。这个参数在排查网络文件系统时特别有用如果你发现df执行非常卡顿很有可能是NFS挂载的远程目录失联或超时df会卡在那里等IO。处理方式是先检查NFS挂载状态或者把失联的挂载点卸载。系统启动时自动挂载的配置在/etc/fstab里如果NFS挂载点出问题系统启动也可能卡住。df -T能帮你快速看哪些是网络文件系统以便调整排查策略。还有tmpfs类型的挂载点如/dev/shm占的是内存空间大小和内存有关不能按磁盘思路清理。6. iostat磁盘IO的延迟、队列和吞吐量分析6.1 先看扩展统计别用默认输出Linux自带的iostat默认输出相当有限只有tps和KB_read/s等简单信息很难判断瓶颈。实际排查都用iostat -x -d 1-x表示显示扩展统计-d表示只显示设备1是采样间隔。如果要持续看iostat -x -d 1 5就是采样5次。输出里会看到Device、r/s、w/s、rkB/s、wkB/s、avgqu-sz、await、r_await、w_await、svctm、%util等字段。第一次看到这些英文缩写可能发懵但它们其实描述了磁盘每个细分维度的状态。6.2 关键字段的含义和判断经验r/s和w/s是每秒读/写请求次数rkB/s和wkB/s是每秒读写数据量。直接对比可以判断这台磁盘的吞吐是请求多还是数据量大。avgqu-sz是平均请求队列长度队列太长说明请求在排队磁盘处理不过来。await是每次IO请求的平均处理时间毫秒包括在队列里等待的时间和实际处理时间。r_await和w_await则分别拆开读和写。%util表示设备在采样周期内有百分之多少时间在处理IO很多人以为%util到100%磁盘就满了其实对于多盘如硬件RAID或固态硬盘100%也不一定是上限需要综合看。我的实践判断普通机械盘如果await超过20ms甚至30ms说明已经明显变慢SSD通常应在个位数毫秒高负载时会到十几毫秒。%util接近100%且avgqu-sz不断增加说明磁盘确实处于高负载但如果%util高但await不高、队列也短可能是在处理大量小IO并发能力还可以。不能只看单个指标要把队列长度和请求耗时放一起看。6.3 瓶颈方向是磁盘慢还是上层请求太猛如果r/s和w/s非常高先看是什么进程在发起请求。用iotop非默认安装可以按进程显示IO非常直观。没有iotop时也可以用pidstat -d或者从vmstat的bi/bo里看到整体IO量再结合ps和进程行为猜测。磁盘慢时iostat的%util会高但请求量不一定很大有可能是单次IO随机读写、寻道开销大await就会高。而如果请求量大但%util不高则可能是上层应用并发不足和文件系统缓存命中率高实际落盘很少。6.4 实际举例一条iostat输出怎么读比如iostat -x -d 1输出sda r/s20 w/s180rkB/s500wkB/s18000avgqu-sz8.5await35.6r_await12.3w_await39.1%util98。这个场景基本是写多读少写延迟将近40ms队列长度8.5说明每次都排队磁盘已经在满负荷工作。这时如果是数据库就要考虑优化写入模式、批量提交或扩充磁盘能力。如果是日志写入可以考虑异步落盘或换更快的设备。再配合top查看谁在使用CPU可能发现某个进程同步写文件导致整个系统慢这时优化方向就明确了。7. 实战一次模拟数据库卡顿的完整排查链路为了把这五个命令串起来我模拟一次故障过程。某业务系统突然响应变慢运维进去后用top、vmstat、free、df、iostat一步步定位整个过程不复杂但顺序很重要。7.1 进入系统先看toptop -bn1快速看一眼load average发现load已经从正常的2左右涨到914个核心的系统明显过载。进程列表里数据库进程CPU占150%多线程下超过100%正常看起来还行但排在最前面的CPU使用率并不高这就奇怪了。再看CPU状态us约25sy约5wa高达62这是典型IO等待。内存看起来也用了不少free命令显示available只有8G总共64G还有余量但不算宽裕。7.2 vmstat确认阻塞点是IO执行vmstat 1 5第一行忽略看后面四行r大概在3到5之间b却几乎一直是2或者3。b持续非0说明有进程卡在不可中断睡眠状态而这类状态多数是等磁盘。si/so为0排除swap压力。cs上下文切换每秒接近4万有点高但结合wa高更像是IO阻塞导致的频繁调度。现在基本可以断定瓶颈在磁盘IO不是CPU也不是内存。7.3 iostat定位到具体设备执行iostat -x -d 1 5发现数据库所在的sdb设备%util稳定在99%avgqu-sz一度到15await平均值到45ms。这说明磁盘确实被压满了。再看r/s和w/s读请求不多但写请求很高wkB/s并不算特别大说明是大量小写请求把队列堆满了。数据库每秒写很多小事务随机写导致磁盘寻道压力大机械盘特性直接被放大。7.4 df和inode核查顺手执行df -h和df -i空间很充足inode使用率也只有30%排除磁盘满和inode满。到这里问题根因明确数据库日志或频繁小事务写入导致磁盘IO饱和。进一步检查发现应用层开启了同步提交或同步刷盘配置每次事务都强制写盘。调整批量提交策略缓冲一段时间再写实测tps恢复load回落到2.5wa降到10%以下。7.5 这个排查链路的通用价值整个过程中top给总体方向vmstat确认瓶颈类型iostat定位设备free和df排除内存与空间干扰。这五条命令顺序执行十几分钟就能有一个明确结论不需要装额外工具。在生产环境中这种排查思路可以复制到很多相似的性能问题里并不是某个特定数据库的专属套路。8. 我把这些命令用熟的几个经验和坑8.1 用watch命令让输出自动刷新排查现场想持续观察top、vmstat或iostat不要开几十个终端窗口。用watch -n 1 vmstat 1 2既能看到两次采样又保持屏幕稳定。也可以watch -d free -h-d会高亮变化的部分长时间观察内存增长特别有用。iostat用watch刷新时建议用iostat -x -d 1 2别用iostat -x -d 1否则默认只输出一次就结束了刷新窗口。8.2 采样时间别太短尤其别拿单点下结论很多人执行vmstat或iostat只取一次第一次输出的还是系统平均或者瞬时值很容易误判。比如某应用每5秒做一次大IO单次看wa可能只有10%连续看10个点就能发现规律。我几乎不会用单次结果做判断至少要连续采样3次以上。采样期间如果系统负载刚起来也得留出时间让负载充分体现否则看到的都是过渡状态。8.3 这些命令在精简系统里可能没有有些容器或最小化系统里iostat不在因为sysstat包没装。这时候可以先看/proc/diskstats、/proc/stat、/proc/meminfo它们提供底层数据。vmstat某些老版本没有available字段可以看free命令的available或者读取/proc/meminfo的MemAvailable。生产环境想用工具最好提前在镜像或安装脚本里备好sysstat、procps等基础包别等故障了再发现装不上或没权限。8.4 远程操作时小心终端卡住在慢终端或网络抖动时执行top全屏交互式如果中途卡住可能回不到命令行。习惯做法需要采集输出时用top -bn1代替top需要观察趋势时结合watch或重定向输出到文件。重定向之后还能事后分析比如top -bn1 top_$(date %s).log配合脚本生成汇总。最后再分享一个小习惯我会把一次完整的排查记录全部存下来包括top、vmstat、free、df、iostat的输出和最终处理动作。下次遇到类似问题翻记录比拍脑袋快得多。这些命令真正有价值的地方不是单条输出而是组合起来之后能告诉你系统正在经历什么。希望你也能把这套思路用在日常运维里。