Linux性能分析方法论:USE、RED、火焰图与perf实战

工具会用,不等于能定位问题。很多人手里攥着 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% 忙)
  • 饱和度:有多少工作在排队?(如运行队列长度)
  • 错误:有报错吗?(如网卡丢包、磁盘错)

一张表覆盖所有资源

资源 使用率 饱和度 错误
CPU mpstat 的 %usr+%sys vmstat 的 r 列 dmesg 里 MCE
内存 free 的 used vmstat 的 si/so、OOM dmesg 的 OOM
磁盘 iostat 的 %util iostat 的 aqu-sz smartctl、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 火焰图
想证明优化有效 改前改后基线对比
最难的一步 明确定义「慢」,并对齐时间线

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

相关推荐
问心无愧05131 小时前
[ACTF2020 新生赛]Exec
运维·服务器·笔记
cg.family1 小时前
K8S:scale 与 delete pod 核心区别
运维·docker·容器
微订校园外卖平台1 小时前
同城外卖跑腿平台需要服务器吗?交付方式、部署架构与上线核对
服务器·架构·github·外卖系统·本地生活·微订
发量惊人的中年网工1 小时前
游戏出海服务器选哪个IDC?开服卡顿、延迟抖动的排查与选节点思路
服务器·idc
开开心心_Every1 小时前
黄金价格软件国内外价格实时监控超方便
运维·服务器·游戏·智能手机·pdf·lua·perl
云中双月1 小时前
瑞芯微rv1106进入Loader模式转储emmc数据
linux·嵌入式·uboot·u-boot·emmc·rockchip·烧录·rv1106·瑞芯微
yunwei371 小时前
eBPF 入门实践教程:BPF Token,安全的委托式权限与程序加载
linux·后端·性能优化
Initialize293081 小时前
systemd 服务起不来?五步排查法
运维
LMT_Lanmantech1 小时前
HyperWorks许可:almutil显示Unit满了,数据到底准不准?
运维·服务器·算法