恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
USE方法实战:Linux性能瓶颈定位从入门到精通
首页
资讯中心
/
USE方法实战:Linux性能瓶颈定位从入门到精通
USE方法实战:Linux性能瓶颈定位从入门到精通
发布时间:2026/9/20 11:50:29
做 Linux 性能排查这些年我越来越依赖一套叫 USE 的方法论来解决 CPU、Memory、Disk、Network 的瓶颈定位问题。USE 不是某个具体工具而是一套检查思路把每个资源拆成 Utilization、Saturation、Errors 三个维度分别看它忙不忙、有没有排队、有没有报错。一开始我也怀疑它是不是把简单问题复杂化了但用了十几套线上故障之后我确认这就是性价比最高的定位方式。这篇文章适合刚从 top 玩到眼花、但面对高负载不知道从哪下手的运维和 SRE也适合后端开发想搞懂服务器资源瓶颈。我会用实际排查案例把命令、参数、判断逻辑一次讲透。1. USE 方法的核心从“看指标”到“找瓶颈”1.1 Utilization、Saturation、Errors 分别回答什么问题你可以把服务器上的每个子系统想象成一根水管。Utilization 回答的是水管里有多少截面积被水占了Saturation 回答的是进水口排了多少人在等Errors 回答的是水管有没有漏水甚至爆裂。把这三个问题分开定位思路就会清晰很多。Utilization利用率描述资源在一段时间内处于工作状态的比例。比如 CPU 有 70% 时间在计算磁盘 85% 时间在忙。高利用率不代表一定有问题关键看业务有没有被拖慢。Saturation饱和描述资源已经排队等待的任务量。CPU 的 run queue、内存的 swap 换页、磁盘的 avgqu-sz、网络发送和接收队列的 drop都属于饱和信号。饱和升高意味着请求来了但没被及时处理这是性能恶化的直观体现。Errors错误描述资源层的错误事件。比如 CPU 的 machine check、内存的 ECC 报错、磁盘的 I/O error、网卡的 dropped packets。错误类问题往往不能靠调优解决而是硬件、驱动或固件层面的事。为什么要分成三块因为利用率高而饱和低说明资源被充分使用且处理得过来饱和升高说明肉眼可见的延迟问题要出现了错误一旦出现轻则性能劣化重则直接宕机。很多人只盯着 top 里的 %CPU进程都跑满了却不知道下一步该看什么就是因为没有把这三个维度分开思考。1.2 为什么 USE 方法比“盯着 top”高效过去我排查故障习惯一口气敲top、free、df -h、ping敲完感觉每个指标都正常可业务就是卡。后来发现症结在于你没有一个完整的检查清单很容易被某几个显眼的指标带偏比如 load average 不高就排除了 CPU结果真正的问题藏在磁盘等待里。USE 方法的好处是强制你按“资源维度”做完整检查。它的三个约束非常关键第一从资源出发而不是从进程出发第二每个资源只查利用率、饱和度和错误三类指标第三检查顺序优先 Errors其次 Saturation最后 Utilization。这个顺序有讲究错误往往能直接定性饱和能体现当下的实际影响利用率只是一种背景参考。写到这里也顺便提一句USE 和 TSA线程状态分析不是互斥的。USE 适合先做系统级的资源扫描TSA 适合锁到某个进程后看它的线程到底卡在 R、S、D 哪个状态。实战中我通常先用 USE 锁定子系统再用pidstat、perf或strace进入进程内部两条腿走路才不会绕远。2. 搭建你自己的 USE 检查清单2.1 拿到手先干三件事uptime、dmesg、top每次被喊去处理“服务器不对劲”的问题我第一件事不是立刻跑各种指标而是让自己先建立三个基线负载基线、内核/硬件错误基线、进程现状基线。这三件事 30 秒能做完但能省掉后面 30 分钟的瞎猜。uptime看 1/5/15 分钟 load average快速判断问题是持续还是突发。load average 要结合 CPU 核数看8 核机器 load 8 说明刚好占满load 16 就说明任务排了一大队。dmesg -T | tail -n 30这一步被很多人跳过但内核环形缓冲里经常藏着 OOM、ext4 报错、NIC link down、软锁死等关键信息。尤其要盯有没有Out of memory、blocked for more than 120 seconds这类字眼。top -bn1看当前进程排序和整体状态留意 CPU 百分比、内存总量与 Swap也要注意有没有大量进程处于 D 状态不可中断睡眠。注意dmesg 在不同系统上权限不一样。CentOS 7 默认限制了普通用户读取内核日志Ubuntu 20.04 则宽松一些。生产环境建议把kernel.dmesg_restrict配好或者给排查账号 root 权限别等故障时被权限卡住。2.2 一张表格构建四个子系统的 USE 矩阵下面这张表是我自己整理后贴在公司文档里的可以覆盖绝大多数 Linux 性能排查场景。不需要背命令但需要知道每个维度对应哪一类信号。子系统Utilization利用率Saturation饱和Errors错误CPUmpstat -P ALL的 %utiltop 的 %Cpuvmstat 1的 r 列uptime的 load averagedmesg中 soft lockup / machine check/proc/sched_debug 异常Memoryfree -h的 available/proc/meminfo的 MemAvailablevmstat 1的 si/so 连续非零swap 使用量dmesg 中 OOM 日志systemd 日志中 “Out of memory”Diskiostat -x 1的 %utilsar -d的 %busyiostat -x 1的 avgqu-sz、await/proc/diskstats中 io_in_progressdmesg 中的 I/O errorSMART 告警smartctl -HNetworksar -n DEV 1 1的 rxkB/s / txkB/s 与网卡带宽比ifstatss -s中 send-q / recv-q 大小netstat -s中的丢包、重传ethtool -S eth0的 errors/dropsdmesg 的 NIC link down这张表最容易被忽略的是 Memory 的饱和判断。很多人看到 free 显示还剩几个 G就以为内存没事其实 available 才是真正能分配给新进程的内存。自己算很麻烦直接看free -h的 available 列更靠谱。按这张表走一遍通常能筛掉 80% 的“都不知道从哪里查起”的问题。2.3 采样间隔区分“瞬时抖动”和“持续瓶颈”性能分析最怕拿一个瞬间值来定性。比如iostat -x 1 3连续看 3 次第一次 %util 100后两次 20这种场景大概率是定期任务或初始化造成的抖动而vmstat 1 5中 si/so 每一行都非零才说明内存换页是持续性压力。我的采样习惯是分两个阶段快速判断用vmstat 1 5、iostat -x 1 5、mpstat -P ALL 1 5每次 5 秒确认阶段会把参数改成 60 次、间隔 10 秒或者用sar -o /tmp/perf.sa 5 100后台记录然后看趋势。如果服务器已经接入监控系统优先拉监控图看曲线不要反复登上去手工执行命令尤其不能在高峰期给自己增加负载。提示性能分析命令本身也会消耗资源。机器已经紧张时别反复跑top、iotop、stress这类工具必要时用nice -n 19降优先级执行。分析要尽量“无创”。3. CPU、Memory、Disk、Network 逐个击破3.1 CPU 瓶颈别只看百分比CPU 利用率高只是表象必须分清是用户态、内核态还是软中断消耗。先用mpstat -P ALL 1看每颗核的分布有一个典型的判断点单核 100% 而其他核空闲大概率是单线程程序或锁竞争所有核均匀高负载才更可能是并行任务确实多。vmstat 1的 r 列是关键饱和指标。如果 r 长期大于 CPU 核数说明有线程在排队系统已经算不过来了。另一个不能忽视的信号是上下文切换vmstat里的 cs 列如果长期每秒几十万甚至上百万即使 r 不高也要怀疑应用层在频繁加锁或线程反复唤醒。这时候用pidstat -w 1能看到具体进程的 cswch/s 和 nvcswch/s帮助快速缩小范围。再补一个常见误区top 里%Cpu(s) us高并不一定是业务算法太慢。us高需要 profile 用户态代码sy高则要查系统调用、中断、锁竞争sisoftirq高就要关注网络收包和网卡驱动。我有一次排查线上问题始终是 us 30% 加 sy 60%一开始以为是业务逻辑开线程太多后来发现是网卡驱动触发了大量 softirq收包把 CPU 打爆了。方向错了后面再优化代码都没用。3.2 Memory 瓶颈理解 available 与 swap内存利用率要先明确一点free命令显示的free列接近 0 时系统依然可能很健康因为 Linux 会把空闲内存拿去当 page cache内存真的不够时会自动回收这部分。真正应该看的是 available 列这个值是“在不触发 swap 的前提下还能分配多少内存”的参考。内存饱和最直接的证据是vmstat 1里 si 和 so 持续非零。si 是 swap inso 是 swap out只要持续出现基本可以确认物理内存不足导致换页。另一个更细的信号是 PSIPressure Stall Information在/proc/pressure/memory里面可以看到内存压力导致的停顿时间比例。内核 4.20 和 cgroup v2 支持这个特性排查容器内存尤其好用。内存层的严重错误是 OOM kill。一旦 dmesg 里出现Out of memory: Killed process不要急着调vm.overcommit_memory先确认被 kill 的进程是不是容器或 Java 应用再看当时的 cgroup 内存限制有没有配错。很多场景并不是系统物理内存不够而是容器 memory limit 打满被 cgroup OOM killer 强制回收。真正的排查姿势是看memory.events里的oom_kill次数顺便用pidstat -r 1观察内存增长趋势定位是不是有泄漏。3.3 Disk 瓶颈区分延迟高和吞吐慢磁盘是 USE 方法里最容易误读的子系统。iostat -x 1的 %util 对现代 NVMe SSD 很不可靠因为 %util 表示设备忙的时间占比而快速设备可能在 100% 忙的情况下依然能处理海量请求。对于 SSD更该关注avgqu-sz平均队列长度、await平均 I/O 延迟和r_await/w_await的拆分。判断阈值建议参考设备基准机械盘 await 往往在 10ms 以上SATA SSD 约 1-3msNVMe 约 0.1-0.5ms。如果await明显高于基准说明请求在排队或者设备开始老化如果await很高但 %util 不高可能是应用层发出的 I/O 太碎块设备合并效率低如果avgqu-sz持续大于设备队列深度机械盘典型 32SSD 多为 32-64说明压力超过设备处理能力饱和已经发生了。定位到具体进程时我的组合是iostat -x 1先确认哪块盘有问题再用iotop -o或pidstat -d 1找到是哪个进程在疯狂读写。文件系统层面如果还想更深入可以配合strace -p看系统调用但日常场景下 iotop 和 pidstat 已经足够。要注意数据库服务器上await高并不一定等于磁盘坏可能是后台全量扫描、文件系统日志抖动甚至另一个 cgroup 里的日志进程在抢 I/O所以一定要交叉验证。3.4 Network 瓶颈从带宽到连接队列网络性能分析分好几层物理网卡、协议栈、连接队列、应用层。USE 方法在网络上同样适用。Utilization用sar -n DEV 1 1看 rxkB/s、txkB/s 和 pkt/s。比如网卡是 10Gbps理论最大约 1.25GB/s如果 rxkB/s 已经跑到 1GB/s确实接近带宽上限。但小包高并发场景很特殊可能rxpck/s很高而rxkB/s不高瓶颈反而在 CPU 中断处理。Saturation看协议栈的丢包和重传。netstat -s里TCPLostRetransmit、SYNs to LISTEN sockets dropped、times listened socket queue overflow都是非常明确的饱和信号说明连接已经排队到溢出。ss -lnt中 Recv-Q 如果持续堆积说明应用层没有及时消费数据。Errorsethtool -S eth0里rx_crc_errors、tx_dropped、rx_missed_errors属于硬件层问题dmesg 里出现Link is Down则说明物理链路抖动过这是网卡、光纤或交换机的故障前兆。一个典型例子Nginx 前出现大量 TIME_WAITss -s显示几万个 TIME_WAIT 连接新连接建立变慢。这个问题的本质不是带宽不够而是应用层短连接太频繁。调优方向包括开启net.ipv4.tcp_tw_reuse、扩大net.ipv4.ip_local_port_range、让客户端复用连接。值得注意的是不同内核版本对 tcp_tw_reuse 的行为不一样必须基于自己的内核版本做验证不能照抄网上配置。4. 实战案例一次典型的“load average 高”排查4.1 场景描述与初始判断有一次线上报障某 8 核云服务器业务响应变慢值班同事先看了top发现 load average 已经到 28 了但 CPU 使用率只有 30%内存也只用了 60%。如果只看这些表象很容易得出“CPU 不够”的结论然后盲目扩容但这样通常解决不了问题。我登录后先跑uptime确认 1/5/15 分钟负载都很高说明持续了不短时间。紧接着执行dmesg -T | tail -n 30没发现 OOM 和硬件错误。然后用vmstat 1 5看饱和信号输出如下示例procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 7 0 1048576 2048 8388608 0 0 0 1024 123 456 8 4 60 28 0 0 8 0 1048576 2048 8388608 0 0 0 11264 134 470 8 5 55 32 0 0 8 0 1048576 2048 8388608 0 0 0 10890 130 489 8 5 54 33 0注意 r 列接近 0这排除了 CPU 排队但 b 列一直有 7-8 个进程处于阻塞状态而且在 io 的 bo 列持续有大量块写7 台机器的 waI/O wait一直占 30% 上下。到这里基本可以锁定问题在磁盘饱和不是 CPU 也不是内存。4.2 真凶是磁盘饱和接下来执行iostat -x 1 5输出的关键行类似Device r/s w/s ... avgqu-sz await r_await w_await %util vdb 12.00 1024.00 ... 80.00 78.50 2.00 90.10 100.00avgqu-sz到了 80await到了 78.5ms%util100%。机械盘或普通云盘出现这个组合基本就是磁盘队列被塞满。继续用pidstat -d 1找进程输出显示某个日志采集进程的写速率占了大头同时iotop -o里能看到它一直在 D 状态写盘。处理办法分两步先止损把这个日志采集进程的 I/O 优先级调低用ionice -c2 -n7 -p PID让它在系统繁忙时让路再治本检查日志轮转脚本发现每行日志都触发了刷盘调整成批量 flush 后磁盘队列立刻降下来了。这个案例如果用 USE 方法走到磁盘只花了 10 分钟如果只在 top 里猜 CPU 问题可能浪费半天去扩容和调应用。还有一点值得单独说为什么 CPU 不高 load 却暴涨因为 Linux 的 load average 统计的是 R 和 D 状态的进程数D 状态进程阻塞在磁盘 I/O 上同样会被算进去。所以磁盘排队时load 完全可能飙到很高这就是“CPU 很闲但系统却很卡”的典型场景。4.3 如果只保留三条命令我会保留哪三条实战里如果要压缩到极限我建议保留uptime、vmstat 1 5、iostat -x 1 5。uptime给整体印象vmstat分辨 CPU/内存/阻塞方向iostat确认磁盘饱和。跑完这三条大多数“高负载但不知道原因”的问题已经能定位到子系统。剩下的再用pidstat和ss往深处追。5. 常见问题与排查技巧实录5.1 指标误读iostat %util、load average、free 的 available先列三个最容易误导人的地方iostat的 %util 对 SSD 不等于“饱和”。%util 是采样周期内设备 busy 的占比SSD 处理速度快%util 100% 可能依然能扛住业务队列长度才是更可靠的饱和信号。load average 不是 CPU 使用率。它统计运行队列里的任务数包括 D 状态在内。所以磁盘阻塞、NFS 挂死都会拉高 load但 CPU 使用率不高。遇到 load 高先看vmstat的 r 和 b 列别急着加 CPU。free的 free 列不代表可用内存。Linux 的 page cache 会在需要时释放真正有参考意义的是 available。你可以用cat /proc/meminfo查看 MemAvailable它是内核计算出的“不触发 swap 的可分配内存”。这几个误读我几乎每次带新人排查都会遇到尤其是第一个相当多人把 %util 当成磁盘性能的“金标准”最后方向全错。5.2 短时峰值与采样遗漏以及用什么补短时峰值是排查中最容易漏掉的点。手工执行命令只能看到当前几秒的瞬时状态如果问题发生在深夜或上下班高峰期你登录时可能已经恢复正常了。解决方案有三种后台 sar、监控系统、perf 采样。后台 sar提前开sar -o /tmp/perf.sa 5 100 它会在后台记录 CPU、内存、磁盘、网络历史事后用sar -f /tmp/perf.sa回放。监控系统生产环境强烈建议用 node_exporter Prometheus 或类似方案至少保留 30 天的资源指标。很多“刚刚突然卡了一下”的故障都能从监控图里找到对应时间点的异常指标。perf 采样如果怀疑是应用层锁或热点函数可以在问题窗口用perf record -g -F 99 -p PID采集几十秒然后perf report看调用栈。这属于 CPU profiling 的一部分适合深入定位。5.3 千万不要忽略 Errors 层Errors 层是 USE 方法里最容易被跳过的。很多人看到利用率高、饱和高就直接去调优或扩容但我见过不少案例真正的根因是硬件已经报错但没被发现。比如磁盘扇区重映射、网卡 RX errors 飙升、内存 ECC 单比特翻转这类问题不会永远在日志里刷屏但会持续拖慢性能。快速扫错误的命令组合我放在一起dmesg -T | tail -n 100 journalctl -k --since 1 hour ago | grep -iE error|oom|soft lockup|hung task netstat -s | grep -iE drop|retrans|overflow|error ethtool -S eth0 | grep -iE error|drop smartctl -H /dev/sda如果这几条全是干净的再放心去调优。只要里面任何一项有异常优先处理硬件或驱动问题否则后面所有优化都可能白做。5.4 建立自己的 USE 检查脚本为了不每次故障都重新敲一遍命令我写了一个很小的脚本放到/usr/local/bin/usecheck本质就是把前面提到的检查步骤串起来。你可以直接复制这一段#!/bin/bash echo load ; uptime echo dmesg tail ; dmesg -T | tail -n 20 echo memory available ; free -h echo cpu utilization ; mpstat -P ALL 1 3 echo saturation: vmstat ; vmstat 1 3 echo disk ; iostat -x 1 3 echo net throughput ; sar -n DEV 1 3 2/dev/null || ifstat -t 1 3 echo net errors ; netstat -s | grep -iE drop|retrans|overflow|error | head -n 20保存后chmod x /usr/local/bin/usecheck接到报警先跑一遍。注意脚本里的sar和iostat来自 sysstat 包ifstat可能需要单独安装。这个脚本不追求一次定位根因但能让你在几分钟内把 USE 的检查表走完把范围缩小到某个子系统。6. 写给后来者的一些个人心得用 USE 方法排查了几年我最大的体会是它不是我背下来的那堆命令而是我在现场的第一直觉当一个指标不正常我会先问自己这个资源到底是在忙、在排队、还是在报错每一步都基于这个判断往下走效率提高了非常多。最后送大家一个小技巧把上面的 usecheck 脚本放到 PATH 里接到报警先跑一遍大概率能看到明确方向。别急着调优参数先把瓶颈找对。这个思路同样适用于容器环境把宿主机资源和 cgroup 资源叠着看很多莫名其妙的问题都能第一时间收敛到一个具体的子系统上。