资讯动态

Linux CPU指标真相:vmstat/mpstat/top/sar四工具协同诊断

发布时间:2026/10/22 19:50:02 来源:尧图企业网站定制
1. 为什么“看CPU使用率”这件事90%的人从一开始就没看对“CPU使用率85%——系统快崩了”“top里显示idle只有5%赶紧扩容”“sar -u输出的%idle和%user加起来不到100%是不是工具坏了”我在某公司做系统稳定性保障的第三年接手的第一个跨部门告警复盘就是被这样一条“CPU持续超阈值”的告警牵着鼻子跑了整整两天。监控平台标红、告警短信刷屏、应用日志里满屏的“线程阻塞”可当我连上那台被标记为“罪魁祸首”的服务器用top扫了一眼CPU idle稳定在62%user 28%sys 9%iowait 0.3%——一切正常。最后发现是上游服务因网络抖动重试激增把下游这台机器的连接队列打满请求在内核协议栈排队而top和vmstat看到的“CPU空闲”恰恰掩盖了真正的瓶颈TCP接收缓冲区溢出导致的SYN队列堆积。这就是现实CPU使用率从来不是孤立指标它是一面镜子照出的是整个系统协作链路的状态而不是CPU本身是否“累”。你看到的85%可能是Java应用在疯狂GC实际CPU在干等内存回收也可能是MySQL在做全表扫描CPU在算但磁盘IO早已拖垮还可能是某个Python脚本在死循环里调用time.sleep(0.001)——它几乎不占CPU却让调度器反复唤醒又挂起把%sys悄悄推高。所以这篇内容不教你怎么敲top回车而是带你亲手拆开vmstat、mpstat、top、sar这四把“老式机械表”看清它们各自测量的是哪一段齿轮的转速、哪一根游丝的震颤、哪一处发条的松紧。你会发现vmstat的r字段运行队列长度比%cpu更能预判雪崩mpstat -P ALL里某个逻辑CPU的%iowait长期高于15%往往意味着磁盘队列已成堰塞湖top默认的%CPU是进程级采样均值而htop里按F4过滤后的实时峰值才是压测时真正要盯死的数字sar -u的%steal一旦非零你的虚拟机早就被宿主机“抽血”了再调优应用代码都是徒劳。这些不是玄学是Linux内核调度器、CFS公平队列、tickless机制、perf事件子系统共同写就的底层契约。接下来我会用一台实测的4核8G云服务器模拟项目X的生产环境逐个拧开这四把工具的后盖告诉你每个数字从哪来、信几分、何时该信、何时必须扔掉重看。2. vmstat运行队列与上下文切换——CPU压力的“前置哨兵”vmstat的名字容易让人误解——它其实和“虚拟内存”virtual memory关系不大而是vmvirtual memory manager的缩写核心职责是监控内核调度层的关键状态。它的价值不在CPU百分比而在那几个看似枯燥的整数r、b、cs、in。2.1 为什么r值比%cpu更早发出危险信号先看一组实测数据。我在模拟项目X中启动一个压测脚本目标是让单核CPU达到70%利用率# 压测前 baseline $ vmstat 1 3 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1245678 89234 456789 0 0 12 34 123 456 5 2 93 0 0 # 压测中仅1秒采样 $ vmstat 1 3 r b swpd free buff cache si so bi bo in cs us sy id wa st 3 0 0 1234567 89234 456789 0 0 15 36 125 489 28 12 60 0 0 4 0 0 1234567 89234 456789 0 0 14 35 124 492 29 13 58 0 0 5 0 0 1234567 89234 456789 0 0 16 37 126 495 30 14 56 0 0注意r列从0跳到3、4、5。此时top显示的%CPU才刚到28%。r代表当前等待CPU时间片的进程/线程数量即运行队列长度。Linux内核的CFS调度器有一个隐含规则当r值持续大于逻辑CPU核心数这里是4说明调度器已经开始“排队叫号”即使CPU当前没满延迟必然上升。提示r值的安全阈值不是固定值。经验法则是r 0.7 * CPU_cores为健康r CPU_cores需警惕r 2 * CPU_cores大概率已出现可观测延迟。本例中r5 4正是压测脚本开始抢占资源的明确信号。2.2cs上下文切换暴露出的“伪高CPU”陷阱继续压测我故意让脚本创建大量短生命周期线程模拟某SDK的错误用法$ vmstat 1 3 r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 0 1200000 89234 456789 0 0 18 40 130 2500 15 45 40 0 0 2 0 0 1199000 89234 456789 0 0 17 39 129 2520 16 44 40 0 0 2 0 0 1198000 89234 456789 0 0 19 41 131 2550 17 43 40 0 0r稳定在2健康但cs飙升到2500正常值应1000us仅15%sy却高达45%。这意味着CPU大部分时间花在内核态的线程切换开销上而非执行用户代码。top里看到的“高CPU”其实是%sy在撑场面根源是应用层滥用线程池频繁pthread_create/pthread_join。注意cs值需结合in中断次数看。若in也同步飙升可能是硬件中断风暴如网卡软中断绑定不当若in平稳而cs暴涨则100%是软件层线程模型问题。这是vmstat独有的诊断维度top和sar无法直接提供。2.3b字段被遗忘的“不可中断睡眠”预警b列代表处于不可中断睡眠状态D状态的进程数。这类进程通常在等待磁盘IO或硬件响应无法被信号打断。b0本身不危险但若b持续存在且r同步升高说明IO子系统已成瓶颈。我曾遇到一个案例某数据库备份脚本在dd读取大文件时b值从0跳到3并维持10分钟r随之升至6。iostat显示%util已达100%但top的%CPU只有35%。此时vmstat的b字段像一盏红灯明确指向磁盘——而不是CPU。实操心得vmstat最该每5秒运行一次vmstat 5而非1秒。高频采样会加剧cs自身开销反而污染数据。生产环境建议vmstat 5 121分钟快照配合dmesg -T | tail -20查内核OOM或IO错误日志形成闭环。3. mpstat单核粒度的“CPU解剖刀”——识别不均衡与窃取mpstatMultiProcessor Statistics是唯一能穿透top的“平均幻觉”把CPU使用率按物理核心、逻辑CPU超线程逐个摊开的工具。它的核心价值在于两个字不均衡。3.1-P ALL揪出那个“躺平”的CPU核心在模拟项目X的Web服务中我们部署了一个基于NginxPHP-FPM的架构。常规top显示整体CPU 45%一切正常。但mpstat -P ALL 1 3揭示了真相$ mpstat -P ALL 1 3 Linux 5.4.0-xx (host) 01/01/2024 _x86_64_ (4 CPU) 01:23:45 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle 01:23:46 PM all 12.25 0.00 3.25 0.00 0.00 0.25 0.00 0.00 0.00 84.25 01:23:46 PM 0 35.00 0.00 12.00 0.00 0.00 1.00 0.00 0.00 0.00 52.00 01:23:46 PM 1 2.00 0.00 0.50 0.00 0.00 0.00 0.00 0.00 0.00 97.50 01:23:46 PM 2 1.50 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 98.25 01:23:46 PM 3 0.50 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 99.25all行显示平均%idle84.25%但CPU 0的%idle只有52%其他三核近乎空闲。这说明负载完全集中在CPU 0上。根源是Nginx的worker_processes auto;配置在某些内核版本下未正确绑定到多核所有网络中断都路由到了CPU 0。关键原理Linux的IRQ中断请求默认由CPU 0处理。若未配置irqbalance或手动绑定网卡中断高并发连接会把CPU 0彻底打爆而top的平均值会温柔地掩盖这一事实。mpstat -P ALL是唯一能戳破这层窗户纸的工具。3.2%iowait的真相它根本不是“CPU在等IO”这是mpstat及所有工具最常被误解的字段。%iowait常被解释为“CPU等待IO完成的时间占比”但这是严重错误。Linux内核文档明确指出%iowait是CPU处于空闲状态idle且至少有一个进程在等待IO完成时的时间占比。换句话说%iowait 0的前提是%idle 0。如果%idle 0即使磁盘IO已满负荷%iowait也必为0——因为CPU根本没空闲下来“等”。实测验证场景Add if/dev/zero of/tmp/test bs1M count10000 oflagsync强制同步写mpstat输出%idle0.00,%iowait0.00,%sys95%场景Bdd if/dev/zero of/tmp/test bs1M count10000异步写mpstat输出%idle45.20,%iowait38.50,%sys12%踩坑实录某次线上故障DBA坚称“%iowait只有5%IO肯定没问题”但iostat -x显示await高达200ms。我立刻用mpstat -P ALL 1发现%idle为0%iowait自然为0。真实瓶颈是CPU被mysqld的SQL解析占满根本没机会进入idle去“等待”IO。%iowait在此场景下完全失效必须切换到iostat的await和svctm。3.3%steal云环境下的“CPU失窃案”证据在虚拟化环境中%steal是mpstat赋予我们的“上帝视角”。它表示当前虚拟CPU被宿主机调度器强制剥夺steal的时间占比。$ mpstat -P 0 1 3 01:30:00 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle 01:30:01 PM 0 15.00 0.00 5.00 0.00 0.00 0.50 12.50 0.00 0.00 67.00%steal 12.50%意味着CPU 0有超过十分之一的时间本该执行你的进程却被宿主机拿去跑其他租户的任务了。此时无论你怎么优化应用代码性能天花板已被宿主机锁死。经验技巧%steal 5%是严重警告 10%需立即联系云厂商核查宿主机负载 20%基本可判定为“降配”或“超卖”实例。mpstat是唯一能直接量化这种“云原生损耗”的工具top和sar的CPU统计均未剥离%steal。4. top进程级动态视图——如何读懂它的“实时幻觉”top是运维人员的第一反应工具但它呈现的是一幅高度加工过的实时快照而非原始数据流。理解它的刷新机制、排序逻辑和字段含义才能避免被“第一眼印象”误导。4.1 刷新周期与采样偏差为什么top里的数字总在“跳”top默认3秒刷新一次但它的CPU使用率计算并非简单取两次/proc/stat的差值。其核心算法是在刷新时刻T1读取/proc/stat中各CPU时间戳user,nice,system,idle,iowait,irq,softirq,steal等待delay秒默认3秒在T2时刻再次读取/proc/stat计算(T2 - T1)区间内各时间分量的增量除以总增量得到百分比问题在于delay是top内部计时而非精确的3秒物理间隔。当系统负载极高时top自身进程可能被调度器延迟执行导致T2-T1实际远大于3秒。此时计算出的%CPU是“长时间段内的平均值”而非“最近3秒的瞬时值”。实测对比用top -b -n1 | grep Cpu(s)抓取单次快照同时用sar -u 1 1获取1秒精度数据结果top显示%idle75%sar显示%idle62%因top实际采样了4.7秒。解决方案top -d 1强制1秒刷新并观察%CPU列是否稳定。若仍跳变剧烈改用pidstat -u 1——它基于/proc/[pid]/stat的精确时间戳无调度延迟。4.2%CPU字段的隐藏含义它是“进程生命周期内”的均值top中%CPU列的官方定义是“自进程启动以来该进程使用的CPU时间占系统总CPU时间的百分比”。注意关键词自启动以来。这意味着一个已运行24小时、平均占用0.1% CPU的后台进程在top里可能永远排在列表底部。但若它突然在某一秒内爆发占用100% CPU如日志轮转脚本top的%CPU列只会缓慢爬升无法反映这一秒的尖峰。我曾用stress-ng --cpu 1 --timeout 5s测试进程启动后第1秒top显示%CPU20%第3秒%CPU45%第5秒结束%CPU60%而非100%关键技巧按ShiftP按CPU使用率排序再按R反转可快速定位“近期活跃但历史均值低”的进程。更精准的做法是ps -eo pid,ppid,cmd,%cpu --sort-%cpu | head -20ps的%cpu是“自上次更新以来”的增量更接近实时。4.3VIRT、RES、SHR内存字段的“三重幻觉”top右侧的内存列常引发误判VIRTVirtual Memory进程申请的全部虚拟地址空间包含已分配未使用、共享库、mmap映射等。VIRT大≠内存占用高。RESResident Set Size进程当前实际驻留在物理内存中的大小。这是最该关注的指标。SHRShared MemoryRES中与其他进程共享的部分如libc.so。SHR越高说明进程越“绿色”。陷阱案例某Java应用VIRT5GRES1.2GSHR800M。运维认为“内存泄漏”重启后RES仍缓慢增长。最终发现是JVM的-XX:MaxDirectMemorySize设置过大VIRT包含大量未使用的堆外内存映射而RES增长源于ByteBuffer.allocateDirect()的真实分配。实操口诀看内存压力盯RES忽略VIRT看内存效率算SHR/RES比值0.5说明共享充分RES持续增长且SHR不增才是真正的泄漏信号。5. sar历史数据的“黑匣子”——如何用它还原事故现场sarSystem Activity Reporter是四者中唯一能回溯历史的工具。它不提供实时视图但能回答所有“当时发生了什么”的终极问题。它的威力取决于你是否提前开启了sysstat服务。5.1sar -u的完整字段解密%guest与%gnice的业务意义sar -u输出的字段远比top丰富字段含义业务解读%user用户态程序CPU时间应用代码、脚本执行%nice低优先级nice值0用户态时间手动降权的批处理任务%system内核态时间系统调用、中断处理、内存管理%iowaitCPU空闲且有IO等待的时间仅当%idle0时有效见前文%steal虚拟CPU被宿主机窃取时间云环境性能基线标尺%guest运行客户机Guest OS的时间容器化环境%guest高说明容器密集%gnice运行低优先级客户机的时间容器QoS策略生效在模拟项目X的容器集群中我们部署了10个Nginx容器。sar -u 1 5显示%guest35.20%,%user28.50%,%steal8.30%这说明宿主机35%的CPU时间在运行这些容器其中8.3%被其他租户抢走。%guest与%user的比值35.2/28.5≈1.24表明容器开销合理未出现过度虚拟化损耗。注意%guest只在KVM/Xen等Hypervisor下有意义。Docker等容器技术通过cgroups限制资源%guest恒为0此时应看%user和%system的分布。5.2sar -q运行队列的“历史温度计”如果说vmstat的r是实时体温计sar -q就是病历本。它记录runq-sz运行队列平均长度、plist-sz进程列表长度、ldavg-11分钟负载均值等关键指标。$ sar -q 1 5 Linux 5.4.0-xx (host) 01/01/2024 _x86_64_ (4 CPU) 01:40:00 PM runq-sz plist-sz ldavg-1 ldavg-5 ldavg-15 blocked 01:40:01 PM 2 245 1.25 1.10 0.95 0 01:40:02 PM 3 248 1.30 1.12 0.96 0 01:40:03 PM 5 252 1.45 1.18 0.98 0 01:40:04 PM 7 258 1.65 1.25 1.02 0 01:40:05 PM 9 265 1.85 1.32 1.05 0runq-sz9且持续上升ldavg-11.85远超CPU核心数4blocked0无D状态进程——这组数据清晰指向CPU计算资源不足而非IO或内存瓶颈。此时扩容CPU比加内存更有效。关键区别load average负载均值是就绪态不可中断态进程的指数衰减平均值而runq-sz是瞬时运行队列长度。sar -q同时提供两者可交叉验证。例如ldavg-1高但runq-sz低可能是短时突发流量已过去。5.3sar数据持久化的生死线/var/log/sa/目录的黄金法则sar的历史数据存放在/var/log/sa/文件名如sa011号数据、sa1515号数据。但很多人不知道sa文件默认只保留7天由/etc/cron.d/sysstat控制每个sa文件是二进制格式不可直接cat必须用sar -f /var/log/sa/sa01读取若sysstat服务未启用sa文件为空sar只能返回当天数据我曾因未检查systemctl status sysstat在故障复盘时发现/var/log/sa/下只有sa25当天而事故发生在23号。紧急补救sudo systemctl enable sysstat sudo systemctl start sysstatsudo cp /var/log/sa/sa25 /var/log/sa/sa23伪造文件sudo sar -f /var/log/sa/sa23 -u 3600按小时聚合经验铁律新服务器上线第一件事sudo systemctl enable sysstat每周检查ls -lt /var/log/sa/确认文件连续性对关键业务将/var/log/sa/挂载到独立SSD并设置logrotate保留30天6. 四工具协同诊断一次真实故障的完整排查链路现在让我们把四把工具拧成一股绳复现一次模拟项目X中典型的“CPU使用率异常”故障排查全过程。这不是理论推演而是我笔记本里贴着键盘的便签纸记录。6.1 故障现象告警突袭与初步扫描时间2024年1月15日 14:23告警host_cpu_usage_percent{instanceweb01} 90% for 5m现象Web服务响应延迟从200ms飙升至2s错误率15%第一步top快速定位耗时10秒top - 14:23:10 up 12 days, 3:45, 1 user, load average: 8.25, 7.90, 7.50 Tasks: 245 total, 1 running, 244 sleeping, 0 stopped, 0 zombie %Cpu(s): 85.2 us, 12.1 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 2.7 si, 0.0 st KiB Mem : 8174520 total, 124567 free, 4567890 used, 3482063 buff/cache ... PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND 12345 www-data 20 0 1245678 456789 123456 R 98.5 5.6 123:45.67 php-fpm结论php-fpm进程吃掉98.5% CPU%sy12.1%偏高load average8.25超4核CPU两倍%idle0。表面看是PHP代码问题。6.2 深度拆解vmstat与mpstat交叉验证耗时2分钟vmstat 1 5r b swpd free buff cache si so bi bo in cs us sy id wa st 8 0 0 1245678 89234 456789 0 0 120 340 850 5200 85 15 0 0 0r8严重排队cs5200超高切换wa0无IO等待→ 排除磁盘瓶颈。mpstat -P ALL 1 302:25:10 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle 02:25:11 PM all 85.25 0.00 14.75 0.00 0.00 0.00 0.00 0.00 0.00 0.00 02:25:11 PM 0 98.00 0.00 22.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 02:25:11 PM 1 75.00 0.00 8.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 02:25:11 PM 2 82.00 0.00 10.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 02:25:11 PM 3 88.00 0.00 12.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00CPU 0的%sys22%远高于其他核平均10%且%idle0→ 怀疑CPU 0被特定中断霸占。6.3 根因锁定sar历史回溯与/proc/interrupts取证耗时3分钟查sar -I SUM中断汇总$ sar -I SUM 1 3 02:26:00 PM INTR intr/s 02:26:01 PM sum 12500.00 02:26:02 PM sum 12800.00 02:26:03 PM sum 13200.00中断频率13K/s远超正常值2K/s。查/proc/interrupts定位设备$ cat /proc/interrupts | grep eth0\|enp0s3 CPU0 CPU1 CPU2 CPU3 16: 12500000 0 0 0 IO-APIC 16-fasteoi eth0100%中断落在CPU 0eth0网卡驱动未启用RPSReceive Packet Steering。最终修复echo f /proc/irq/16/smp_affinity_list将中断分散到所有CPUecho options igb InterruptThrottleRate3000 /etc/modprobe.d/igb.conf降低中断频率重启网卡sudo ifconfig eth0 down sudo ifconfig eth0 up6.4 验证与复盘四工具闭环修复后1分钟top%CPU降至35%load average1.2vmstatr从8→1cs从5200→800mpstatCPU 0的%sys从22%→5%各核负载均衡sar -u历史对比%sys峰值从14

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑