☰
Linux性能分析方法论:USE、RED、火焰图与perf实战
2026/10/17 12:09:09 网站建设 项目流程

工具会用,不等于能定位问题。很多人手里攥着top、iostat、sar,遇到「系统慢」还是乱敲一通,看哪儿都像瓶颈。真正的高手靠的是方法论——一套「怎么切入、按什么顺序查、如何验证」的框架。这一篇讲透性能分析的两大方法论(USE 和 RED)、火焰图的原理与实战,帮你从「工具体力活」升级到「思路技术活」。

一、为什么需要方法论

先看一个典型的反面教材:

程序员小李接到告警「接口超时」。他登录机器,敲了 top, 看到 CPU 10%,觉得没问题;又看 free,内存也够; 最后猜是「网络抖动」,重启了服务。问题暂时好了, 第二天又来了。

没有方法论的排查,就是靠猜和重启。有方法论的人会这样走:

  1. 先明确「慢」的定义:是哪个接口、P99 多少、从何时开始。
  2. 按 USE 检查物理资源:CPU、内存、磁盘、网络有没有饱和。
  3. 按 RED 检查服务本身:请求量、错误率、延迟。
  4. 用perf+ 火焰图钻到代码热点。
  5. 找到根因,改,然后用数据验证。

方法论的价值在于:保证覆盖、减少遗漏、可复现、可解释。下面两个框架是业界公认的两把尺子。

二、USE 方法:面向资源

USE = Utilization(使用率)、Saturation(饱和度)、Errors(错误),由 Brendan Gregg 提出,专门用来系统性地检查每一类资源。

对系统里的每种资源,依次问三个问题:

  • 使用率:资源有多忙?(如 CPU 80% 忙)
  • 饱和度:有多少工作在排队?(如运行队列长度)
  • 错误:有报错吗?(如网卡丢包、磁盘错)

一张表覆盖所有资源

资源使用率饱和度错误
CPUmpstat的%usr+%sysvmstat的r列dmesg里 MCE
内存free的 usedvmstat的si/so、OOMdmesg的 OOM
磁盘iostat的%utiliostat的aqu-szsmartctl、dmesg
网络sar -n DEV带宽ss的Recv-Q、重传netstat -s错误
文件描述符ls /proc/<pid>/fd \| wc -l—Too many open files

实战:一步一步走 USE

# 1. CPU 使用率 + 饱和度 mpstat -P ALL 1 3 # 使用率 vmstat 1 3 # r 列 = 运行队列饱和度 # 2. 内存使用率 + 饱和度 free -h vmstat 1 3 # si/so 恒定,饱和 grep -E "Dirty|Writeback" /proc/meminfo # 3. 磁盘使用率 + 饱和度 iostat -dxm 1 3 # %util / aqu-sz # 4. 网络使用率 + 错误 sar -n DEV 1 3 sar -n EDEV 1 3 # 5. 全局错误 dmesg -T | tail -50

USE 的排查顺序:先找利用率高的、饱和的、有错误的资源。三者中任何一项异常,就是线索。

⚠️ USE 的盲区

USE 只看物理资源。如果所有资源都正常,但应用还是慢,那问题在「应用层」——锁竞争、GC、慢查询、算法复杂度。这时要换 RED。

三、RED 方法:面向服务

RED = Rate(请求速率)、Errors(错误率)、Duration(延迟)。它从「服务/微服务」的视角看问题,特别适合排查「接口慢」这类应用层问题。

三个维度

指标含义工具
Rate每秒请求数(QPS)应用埋点、Nginx 日志、APM
Errors每秒错误数 / 错误率应用埋点、日志
Duration请求耗时分布(P50/P95/P99)APM、链路追踪

关键:Duration 要看分位数,不能只看平均值。平均 50ms 的接口,P99 可能是 3 秒——平均值掩盖了尾部延迟,而用户体验由尾部决定。

与 USE 的配合

  • 服务层异常→ 用 RED 定位是哪个服务、哪个接口。
  • 服务层正常但机器慢→ 用 USE 定位是哪个资源。

两者是互补的:RED 告诉你「哪里慢」,USE 告诉你「为什么慢」。

示例:用日志算 RED

# Nginx 日志里统计每分钟请求数(Rate) awk '{print $4}' access.log | cut -c14-18 | sort | uniq -c # 统计 5xx 错误率(Errors) awk '$9 ~ /^5/ {c++} END {print c}' access.log # 统计耗时分布(Duration,需日志带 $request_time) awk '{print $NF}' access.log | sort -n | awk '{a[NR]=$1} END {print "P50:", a[int(NR*0.5)], "P99:", a[int(NR*0.99)]}'

四、性能分析的通用三板斧

无论用哪套方法论,落地都是这三步:

阶段做什么关键动作
观察收集现象和数据明确「慢」的定义,采集指标
定位缩小范围,找到根因自上而下 or 自下而上,逐层排除
验证证明改动有效改前改后对比数据

观察:先定义「慢」

模糊的「系统慢」没法查。要问清楚:

  • 是所有操作慢,还是某个接口慢?
  • 从什么时候开始?之前有变更吗?(部署、配置、流量)
  • 慢到什么程度?P99 多少?
  • 能复现吗?

这一步偷懒,后面全是白费。

定位:两种切入路线

  • 自上而下:从应用/服务视角(RED)往下,先看哪个服务慢,再看资源。
    • 适合:知道具体哪个接口/服务出问题。
  • 自下而上:从物理资源(USE)往上,先看哪个资源饱和,再看谁用的。
    • 适合:只知道「机器整体变慢」。

验证:用数据说话

改完必须验证,不能凭感觉:

# 改前记录基线 mpstat -P ALL 1 5 > before.txt # 做优化 # 改后对比 mpstat -P ALL 1 5 > after.txt diff before.txt after.txt

没有验证的优化,可能只是猜对了,也可能是问题自己消失了。

五、火焰图:一把看穿 CPU 热点

前面讲的是「方法」,火焰图是「利器」。它把成千上万次采样数据可视化成一棵树,让你一眼看出哪个函数、哪条调用链在吃 CPU。

火焰图长什么样

一张标准火焰图:

┌──────────────────────────────┐ │ main (100%) │ <- 顶层:入口 ├──────────────────┬───────────┤ │ process_data │ parse() │ │ (65%) │ (35%) │ ├────────┬─────────┤ │ sort() │ io() │ │ (40%) │ (25%) │ └────────┴─────────┘

怎么读火焰图(核心规则)

  1. 每一层是一个函数,宽度代表它在采样中占的比例(即 CPU 时间占比)。
  2. 越宽说明占用 CPU 越多,是优化重点。
  3. 从下往上是调用关系:下面的函数调用了上面的函数。
  4. 颜色不重要(通常是随机暖色),只是区分函数。
  5. 看「平顶」:一个宽宽的、没有明显下层的函数,说明时间花在它自己身上(而非它调用的子函数),是热点。

找最宽的、最上面那个「平坦」的方块,就是元凶。

六、perf + 火焰图实战

安装依赖

sudo apt install linux-tools-common linux-tools-$(uname -r) # Ubuntu sudo dnf install perf # Rocky/CentOS

火焰图需要 Brendan Gregg 的 FlameGraph 脚本:

git clone https://github.com/brendangregg/FlameGraph.git cd FlameGraph

四步生成火焰图

# 1. 采样 30 秒,-g 记录调用栈,-a 全系统,-F 99 采样频率 99Hz sudo perf record -F 99 -a -g -- sleep 30 # 2. 导出采样数据为文本 sudo perf script > out.perf # 3. 折叠调用栈 ./stackcollapse-perf.pl out.perf > out.folded # 4. 生成 SVG 火焰图 ./flamegraph.pl out.folded > flame.svg

打开flame.svg,浏览器里就能交互式查看(支持点击放大、搜索函数)。

针对某个进程采样

# 只采样 PID 1234 的进程 sudo perf record -F 99 -p 1234 -g -- sleep 30

用 perf top 快速看热点

来不及做完整火焰图时,perf top实时看函数级热点,够用:

sudo perf top -p 1234
Overhead Symbol 42.30% [.] handle_request 18.10% [.] json_encode 9.50% [k] copy_user_generic_string

⚠️ 常见坑

  1. 采样频率过高:-F 99是常用值,调到 1000 会明显增加开销。
  2. sudo 权限:perf record通常需要 root 或CAP_PERFMON。
  3. kernel.perf_event_paranoid限制:设成 2 时普通用户不能采样,需sudo sysctl kernel.perf_event_paranoid=1。
  4. 符号丢失:看不到函数名(全是地址),说明二进制没带符号表或没装 debuginfo。
  5. Java/Python 应用:默认看不到 JIT/解释器内部函数,需要perf-map-agent(Java)或py-spy(Python)。

七、off-CPU 火焰图:抓住「不在跑」的时间

标准火焰图(on-CPU)只展示CPU 在忙什么。但很多性能问题不是「CPU 忙」,而是进程在等——等锁、等 IO、等网络。这些时间 CPU 是空闲的,on-CPU 火焰图完全看不到。

off-CPU 火焰图记录进程「离开 CPU」的时段和原因,用来分析阻塞和延迟:

# 需要 eBPF/bcc 工具 sudo offcputime -df -p 1234 30 > offcpu.folded ./flamegraph.pl --color=io --title="Off-CPU" offcpu.folded > offcpu.svg

它能回答「进程为什么卡住 3 秒」——因为等某把锁,或等磁盘返回。on-CPU 看热点,off-CPU 看阻塞,两者结合才是完整的性能画像。

八、⚠️ 方法论层面的常见错误

  1. 上来就测,不定基线。不知道「正常」长什么样,就无法判断「异常」。
  2. 只修症状不找根因。重启服务、加机器能暂时缓解,但根因没解决必然复发。
  3. 迷信平均值。CPU 平均 30% 但单核 100%、延迟平均 50ms 但 P99 3s——平均值是最大的谎话。
  4. 一次改多个变量。同时改了三处,出问题不知道是哪处。一次只改一个,验证后再改下一个。
  5. 忽略流量模式。突增流量、定时任务(备份、批处理)会和业务抢资源,排查时要把时间线对齐。
  6. 不做压测就下结论。生产不敢压,就在测试环境用wrk/jmeter/fio复现,有基线才好对比。
  7. 把方法论当死板流程。USE/RED 是「检查清单」,不是「必须按序执行」,凭线索灵活跳转。

九、原理探究:采样 vs 埋点,火焰图为何有效

采样(Sampling)的原理

perf不记录每一次函数调用(那样开销太大),而是每隔固定时间触发一次中断,记下此刻 CPU 正在执行哪个函数。采样几十秒得到几万个样本,统计每个函数出现的频率,就约等于它的 CPU 占比。

采样模式的好处:

  • 开销低(1%~5%),可以对着生产环境跑。
  • 不侵入:不需要改代码、重新编译。
  • 统计有效:样本足够多时,频率收敛到真实的 CPU 时间占比。

代价:它是概率性的,短命函数可能采不到。要抓偶发问题,需要拉长采样时间或提高频率。

为什么火焰图这么有效

火焰图把「调用栈 + 时间占比」编码成「横轴宽度 + 纵向层级」,利用了人眼的两个强项:

  • 对宽度的直觉:一眼看出哪个最宽。
  • 对层级的直觉:一眼看出调用链。

它把「几万行采样数据」压缩成「一张可以直接看结论的图」,这就是它的威力。传统 profiler 给的是排序列表,火焰图给的是结构——谁调用了谁、瓶颈在哪条路径上,一目了然。

从现象到根因的完整链路

把整篇串起来,一个成熟的性能分析流程是:

① 观察:用 RED 确认哪个服务/接口慢,用 USE 扫一遍资源 ↓ ② 缩范围:排除资源饱和 → 问题在应用层 ↓ ③ 定位:perf 采样 + 火焰图,找到热点函数 ↓ ④ 深挖:on-CPU 看计算热点,off-CPU 看阻塞等待 ↓ ⑤ 改:优化算法/加锁策略/改配置/扩资源(一次一个变量) ↓ ⑥ 验证:改前改后数据对比,确认有效

工具是「术」,方法论是「道」。工具会更新换代,top变htop、netstat变ss;但「先观察、再定位、后验证;资源用 USE、服务用 RED;热点看火焰图、阻塞看 off-CPU」这套思路,十年都不会过时。

十、一页速查

场景抓手
不知道从哪查先 USE 扫资源,再 RED 看服务
机器整体慢自下而上:USE
某接口慢自上而下:RED
CPU 热点perf record+ 火焰图
进程卡住off-CPU 火焰图
想证明优化有效改前改后基线对比
最难的一步明确定义「慢」,并对齐时间线

性能分析的正确姿势是:先想清楚问题的定义,再用方法论保证覆盖,最后用采样工具定位到代码。工具会用的很多,思路清醒的很少——这篇的目的,就是让你成为后者。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询