4.6 Linux 系统性能调优实战
预计阅读时间:17 分钟
📖 目录
学习目标
学完本章后,你将能够:
- 掌握 USE 方法论(利用率、饱和度、错误)系统性分析性能瓶颈
- 使用
mpstat、perf、iostat、vmstat等工具定位 CPU/内存/磁盘/网络瓶颈 - 生成并解读 perf 火焰图
- 使用
stress-ng进行压力测试和性能隔离实验 - 调整内核参数(swappiness、脏页回写、NUMA 绑定)
核心知识
- US E 方法论——Brendan Gregg 提出的性能分析框架:对每种资源检查 Utilization(利用率)、Saturation(饱和度)、Errors(错误)
- mpstat——多核 CPU 使用率统计,可查看每核的 user/system/iowait/steal 等细分
- perf——Linux 性能事件采样工具,支持 CPU 周期、缓存未命中、分支预测等硬件事件
- 火焰图(Flame Graph)——将 perf 采样数据可视化为堆叠图,横轴宽度表示 CPU 占用比例
- vm.swappiness——内核使用 swap 交换空间的倾向性(0-100),值越低越少使用 swap
- NUMA(Non-Uniform Memory Access)——多 CPU 架构中,每个 CPU 访问本地内存比远端内存快的架构特性
- iostat——磁盘 I/O 统计工具,%util 反映磁盘繁忙程度,await 反映 I/O 延迟
- cgroups v2——Linux 内核资源隔离机制,可限制 CPU、内存、I/O 等资源
- stress-ng——系统压力测试工具,可模拟 CPU/内存/磁盘/网络负载
知识关联
- 前置知识:2.4:进程管理 进程管理、rhcsa01 磁盘分区与 LVM、4.5:网络故障排查 网络故障排查
- 后续影响:性能调优技能是运维进阶的核心能力,与 3.12:系统监控与告警 监控方案、5.12:eBPF 基础 eBPF 紧密关联
- 配套工具:3.12:系统监控与告警 系统监控(Prometheus+Grafana 长期趋势)、4.5:网络故障排查 网络排查(网络层性能问题诊断)
原理讲解
调优方法论:测量→分析→调整→验证
性能调优最忌讳"猜"——不经测量就调整内核参数。正确的方法是:先测量当前性能指标,分析瓶颈在哪个子系统(CPU、内存、磁盘、网络),然后针对性地调整参数,最后重新测量验证效果。如果调整后没有改善,回滚并重新分析。USE 方法论为这个流程提供了系统性的检查框架。
USE 方法论详解
USE(Utilization、Saturation、Errors)是系统性性能分析的框架——对每个资源检查三个维度:
| 资源 | Utilization(利用率) | Saturation(饱和度) | Errors(错误) |
|---|---|---|---|
| CPU | % user + % system | 运行队列长度、负载均值 | 错误计数/故障(罕见) |
| 内存 | 已使用 / 总量 | swap 使用量、OOM 事件 | OOM Killer 触发 |
| 磁盘 | 设备繁忙时间 % | 等待队列长度 | I/O 错误、smartctl 异常 |
| 网络 | 带宽使用量 / 带宽上限 | 接口溢出、丢包统计 | 重传率、CRC 错误 |
当 Utilization 持续接近 100% 时,通常意味着资源成为瓶颈。Saturation 是更好的预警指标——在 Utilization 到达 100% 之前,Saturation 已经开始增长。Errors 无论多少都是需要立即处理的问题。
火焰图解读
火焰图是 Brendan Gregg 发明的 CPU 热点可视化工具。横轴表示采样占比(越宽的方块占 CPU 时间越多),纵轴表示调用栈(底部是被调用函数、顶部是当前执行函数)。解读关键:关注顶部宽大的方块(这是实际消耗 CPU 的函数),以及调用链中的"瓶颈路径"(从底部到顶部的调用链如果每个节点都很宽,说明这条路径整体有优化空间)。
性能工具矩阵:场景 → 工具
| 分析场景 | 首选工具 | 关键指标 | 辅助工具 |
|---|---|---|---|
| 全局 CPU 概览 | top / mpstat -P ALL 1 | %usr、%sys、%iowait、%steal | uptime(负载均值) |
| CPU 调用链热点 | perf record -F 99 -a -g | 采样占比 top 函数 | FlameGraph 火焰图 |
| 内存与 swap | vmstat 1 / free -h | si/so、available、swap used | sar -r、ps --sort=-%mem |
| 磁盘吞吐与延迟 | iostat -x 1 | %util、await、avgqu-sz、r/s、w/s | sar -d、pidstat -d |
| 磁盘热点进程 | pidstat -d 1 | 单进程读写速率 | iotop(交互式) |
| 网络带宽与错误 | sar -n DEV 1 | rxkB/s、txkB/s、drop、errs | ss -s、ethtool -S |
| TCP 连接与重传 | ss -s / nstat -s | retrans、TIME_WAIT 数量 | tcpdump、nstat |
| 单进程资源占用 | pidstat 1 | CPU/内存/IO 按进程细分 | ps aux |
| 长期趋势与历史回放 | sar(sysstat 后台采集) | 任意历史时刻指标 | Prometheus + Grafana |
使用顺序:先看全局(top/vmstat/iostat)确定瓶颈子系统,再下钻到进程(pidstat),最后用 perf 采样调用栈。sysstat 默认每 10 分钟自动采集一次,是重建"故障前 24 小时现场"的关键数据源,生产服务器务必安装并开启。
为什么用 USE 方法论而不是只看 CPU 利用率
很多运维人员看到 CPU 利用率接近 100% 就判定"CPU 是瓶颈"并加 CPU,但实际上 Utilization(利用率)是最差的瓶颈指标。原因:① 利用率高不代表饱和——CPU 可能忙于处理大量可并行的任务,队列并不长;② 利用率低也不代表没问题——如果进程被 I/O 阻塞(%iowait 高),CPU 空闲但系统仍然慢。USE 方法论通过同时检查三个维度解决这个问题:利用率告诉你"资源用了多少",饱和度告诉你"有多少任务在排队等这个资源",错误告诉你"资源本身是否有故障"。饱和度是更好的早期预警指标——在利用率达到 100% 之前,饱和度(如 CPU 运行队列长度、内存 swap 活动)已经开始增长。
为什么火焰图选择 99Hz 而不是 100Hz
perf record -F 99 中的 99Hz 是精心选择的数值。如果用 100Hz(精确的整数频率),采样定时器可能与系统中的其他周期性事件(如内核 timer tick 的 100Hz/250Hz/1000Hz、网络 NAPI 轮询)产生谐振(共振),导致采样偏向某些特定函数,产生统计偏差。使用质数或非整数频率(如 99Hz、97Hz)可以避免与任何固定频率的系统事件同步,采样结果更接近真实的 CPU 使用分布。这是统计采样中的经典技巧——任何固定周期的采样器都可能与被采样系统的周期产生 aliasing。
NUMA 为什么会影响性能
在多路 CPU 服务器(2路/4路)中,每个 CPU 有自己直连的本地内存,访问远端 CPU 的内存需要通过互联总线(如 Intel QPI/UPI),延迟增加 1.5-3 倍。这就是 NUMA(Non-Uniform Memory Access)架构。如果一个进程的内存被分配在远端 NUMA 节点,每次内存访问都付出额外延迟,整体性能显著下降。排查方法:numastat -p PID 检查进程的内存分布;调优方法:numactl --cpunodebind=0 --membind=0 将进程绑定到同一 NUMA 节点的 CPU 和内存。虚拟化和容器场景中 NUMA 感知尤为重要——VM/容器可能跨 NUMA 节点分配资源,导致性能不稳定。
示例代码
1. USE 方法论快速诊断
# CPU — Utilization 和 Saturation
mpstat -P ALL 1 3 # 每核利用率
sar -q 1 3 # 运行队列(runq-sz)+ 负载(ldavg)
# 内存
vmstat 1 5 # si(swap in)/ so(swap out)> 0 = 内存饱和
free -h # available 接近 0 = 内存压力
# 磁盘
iostat -x 1 3 # %util = 磁盘利用率;avgqu-sz = 饱和度
sar -d 1 3 # tps + await(平均服务时间)
# 网络
sar -n DEV 1 3 # rxkB/s + txkB/s;drop 列 = 错误
ss -s # socket 统计
nstat -s | grep -i retrans # TCP 重传统计(netstat 已废弃)
2. CPU 性能剖析
# 每核使用率分析
mpstat -P ALL 1
# 输出示例:
# 09:30:01 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
# 09:30:02 all 40.5 0.0 12.3 0.2 0.0 0.5 0.0 0.0 46.5
# 09:30:02 0 65.2 0.0 20.1 0.0 0.0 1.2 0.0 0.0 13.5
# 09:30:02 1 35.1 0.0 8.5 1.1 0.0 0.0 0.0 0.0 55.3
# CPU 绑定
taskset -cp 0-3 $PID # 将进程绑定到核心 0-3
# cgroups v2 CPU 限制
systemd-run -p CPUQuota=200% --unit=cpulimit-app /usr/bin/myapp # 限制 2 核
# 查找 CPU 消耗最高的进程
top -b -n 1 | head -20
ps aux --sort=-%cpu | head -10
3. 内存深度分析
# free -h 解读
free -h
# total used free shared buff/cache available
# Mem: 31Gi 8.5Gi 1.2Gi 1.0Gi 21Gi 21Gi
# Swap: 4.0Gi 0.5Gi 3.5Gi
# available = 真正可用的内存(free + 可回收的 buff/cache)
# OOM killer 排查
dmesg | grep -i "out of memory" | tail -5
# 输出: 哪个进程被杀、内存使用情况、score
# NUMA 内存分配
numastat -p $PID # 查看进程的 NUMA 内存分布
numactl --cpunodebind=0 --membind=0 /usr/bin/myapp # 绑定到 NUMA 节点
# 查找内存消耗最高的进程
ps aux --sort=-%mem | head -10
4. perf 火焰图
# 1. 安装 perf
apt install -y linux-tools-$(uname -r)
# 2. 采样
perf record -F 99 -a -g -- sleep 30
# -F 99: 每秒采样 99 次(避免精确 100Hz 与某些定时器共振)
# -a: 所有 CPU
# -g: 调用栈
# 3. 生成火焰图
git clone https://github.com/brendangregg/FlameGraph.git
perf script | ./FlameGraph/stackcollapse-perf.pl > out.perf-folded
./FlameGraph/flamegraph.pl out.perf-folded > flame.svg
# 4. 解读火焰图
# 横轴: 采样占比(越宽 = 耗时越多)
# 纵轴: 调用栈(底部 = 被调用函数,顶部 = 当前执行函数)
# 颜色: 随机(无特殊含义)
# 关注: 顶部宽大的方块和调用链中的"瓶颈函数"
5. stress-ng 压测与 cgroups 隔离
# 安装 stress-ng
apt install -y stress-ng
# CPU 压力(4 个 worker 压 60 秒)
stress-ng --cpu 4 --timeout 60s
# 内存压力(2 个 worker 各分配 256MB)
stress-ng --vm 2 --vm-bytes 256M --timeout 30s
# I/O 压力
stress-ng --hdd 2 --hdd-bytes 1G --timeout 30s
# cgroups v2 性能隔离实验
systemd-run -p CPUQuota=50% -p MemoryMax=512M --unit=stress-test \
stress-ng --cpu 4 --timeout 60s
cat /sys/fs/cgroup/system.slice/stress-test.service/cpu.max
# 输出: 50000 100000 ← 50% CPU 限制已生效
# 配合 perf 同时采样
perf record -F 99 -g -p $(pgrep -d',' stress-ng) -- sleep 30
6. swappiness 与脏页调优实验
# vm.swappiness 控制内核使用 swap 的倾向(0-100,默认 60)
# 高值: 更早开始 swap(适合低内存环境)
# 低值: 更倾向回收页面缓存(适合高内存环境)
# 设置为 10(低 swap 倾向,推荐服务器)
sudo sysctl -w vm.swappiness=10
# 脏页回写参数
sudo sysctl -w vm.dirty_ratio=20 # 脏页占内存 20% 开始同步写
sudo sysctl -w vm.dirty_background_ratio=5 # 脏页占 5% 后台回写
# 大文件写入场景: dirty_ratio 调大(容忍更多脏页,减少回写频率)
# 低延迟场景: dirty_ratio 调小(更频繁回写,但单次延迟更低)
7. 基准测试工具
# CPU 基准
sysbench cpu --threads=4 run
# 磁盘 I/O 基准
fio --name=randwrite --rw=randwrite --bs=4k --size=1G --numjobs=4 --runtime=60 --group_reporting
# 网络带宽基准(服务端先运行 iperf3 -s)
iperf3 -c server_ip
# 内存延迟基准
lmbench # apt install lmbench
8. 网络性能调优参数详解
# /etc/sysctl.d/99-netperf.conf
# TCP 窗口缩放(大带宽长链路必开,配合 BDP 自动计算)
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 1
# 放大 TCP 读写缓冲区上限(默认约 6MB,Ubuntu 24.04 的 6.8 内核;高带宽链路可放大)
net.ipv4.tcp_rmem = 4096 131072 6291456
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# 连接队列与端口资源(高并发短连接场景)
net.core.somaxconn = 65535 # accept 队列上限(Nginx 需同步配置)
net.ipv4.tcp_max_syn_backlog = 65535 # SYN 半连接队列
net.ipv4.ip_local_port_range = 1024 65535 # 出站端口范围
net.ipv4.tcp_tw_reuse = 1 # 安全复用 TIME_WAIT(仅出站)
net.ipv4.tcp_fin_timeout = 30 # FIN_WAIT_2 超时
# 长连接保活(穿透 NAT/防火墙场景,防被空闲切断)
net.ipv4.tcp_keepalive_time = 120
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# 生效与验证
sudo sysctl -p /etc/sysctl.d/99-netperf.conf
sysctl net.core.somaxconn
# 注意: tcp_tw_recycle 在 Linux 4.12+ 中已被移除,在新内核上执行会报错;且在 NAT 环境下也会导致连接异常,切勿使用
9. 磁盘 I/O 调度器与挂载参数调优
# 查看当前 I/O 调度器
cat /sys/block/sda/queue/scheduler
# 输出: [mq-deadline] none
# 选型: 机械盘/混合负载用 mq-deadline(延迟优先);
# NVMe 高并发随机读写用 none(直通硬件队列)
# 永久设置(GRUB 内核参数)
# 编辑 /etc/default/grub,GRUB_CMDLINE_LINUX 追加:
# elevator=mq-deadline
sudo update-grub
# 挂载参数: 读多写少场景开启 noatime,省掉每次读文件的 atime 写盘
# /etc/fstab 示例
UUID=xxxx /data ext4 defaults,noatime,nodiratime 0 2
# commit=60: 延长数据提交周期,突发写合并减少 fsync 压力(掉电丢数据窗口相应变大)
# 验证挂载参数
mount | grep /data
# 输出: /dev/sda1 on /data type ext4 (rw,noatime,nodiratime)
# 预读(readahead): 顺序读场景增大,随机读场景保持小值
sudo blockdev --getra /dev/sda
sudo blockdev --setra 4096 /dev/sda
# NVMe 队列深度
cat /sys/block/nvme0n1/queue/nr_requests
echo 1024 | sudo tee /sys/block/nvme0n1/queue/nr_requests
10. 完整调优案例:高并发 Web 服务器
# 背景: 8C16G 云服务器跑 Nginx + PHP-FPM,峰值时延迟从 20ms 飙到 800ms
# 第一步: 测量(USE 快速诊断,先定子系统再动手)
uptime # load 14.5(8 核 → 已饱和)
mpstat -P ALL 1 5 # %iowait 平均 35%(磁盘嫌疑)
iostat -x 1 5 # sda %util 98%, await 45ms
vmstat 1 5 # b 列(阻塞进程)持续 > 10
# 初步结论: 瓶颈是磁盘 I/O,不是 CPU —— 停止"加 CPU"的错误方向
# 第二步: 定位 IO 来源(下钻到进程)
pidstat -d 1 5 # php-fpm worker 每秒写 200MB 到 session 目录
lsof | grep php-fpm | grep deleted # 发现大量已删除仍被打开的文件
# 根因: 访问日志与 PHP session 文件高频写入同一块数据盘 + 未开 noatime
# 第三步: 调整(一次只改一个,每步验证)
# ① access_log 改到独立盘/内存盘,error_log 保留
# ② 重挂 /var 开启 noatime
sudo mount -o remount,noatime /var
# ③ PHP session 迁移到 Redis(参考 ch24),php.ini: session.save_handler = redis
# ④ 小文件高频写场景的脏页参数
sudo sysctl -w vm.dirty_background_ratio=5
sudo sysctl -w vm.dirty_ratio=20
# 第四步: 验证
uptime # 负载回落到 3.2
iostat -x 1 5 # %util 降到 45%
ab -n 10000 -c 100 http://localhost/ # P95 延迟 35ms
# 复盘: CPU 全程未到 100%,真正的瓶颈是磁盘;
# 若第一步就"加 CPU",问题会被掩盖但永远不会解决
常见错误
| 错误表现 | 根因 | 正确做法 |
|---|---|---|
| 看到 CPU idle 0% 就加 CPU | 未区分 %iowait 和 %user,瓶颈可能在磁盘而非 CPU | 用 mpstat -P ALL 1 查看 %iowait;若 iowait 高则检查磁盘而非加 CPU |
| 关掉 swap 后应用被 OOM kill | swapoff 导致内存压力完全由物理内存承担,无缓冲余地 | 设置 vm.swappiness=1 或 10 而非完全禁用 swap |
| free 显示 used 很高就认为内存不足 | 未区分 buff/cache 和真正的 used,Linux 会将空闲内存用做缓存 | 看 available 列(真正可用的内存)而非 used |
| 调整内核参数后性能反而下降 | 一次改多个参数,无法确定哪个改错了 | 一次只改一个参数,改前记录基线值,改后验证效果 |
| NUMA 架构下内存带宽未充分发挥 | 进程跨 NUMA 节点访问内存,延迟显著增加 | 用 numastat -p PID 检查,用 numactl 绑定 CPU 和内存节点 |
| 调整 sysctl 后重启丢失 | 参数只写入运行时,未写入 /etc/sysctl.d/ | 写入 /etc/sysctl.d/99-*.conf 文件,重启后自动生效 |
| 压测数据与线上表现严重不符 | 压测未控制变量:客户端瓶颈、并发模型不同、测试数据过小 | 压测机与被测机分开;用 --numjobs/多客户端拉高并发;每个场景跑 3 次取中位数 |
最佳实践
| 实践 | 原理 | 示例 |
|---|---|---|
| 建立性能基线 | 不知道"正常"是多少,就无法判断"异常" | 新服务器上线后记录 idle 时的 mpstat/iostat/free 数据 |
| 一次只改一个参数 | 改多个参数无法归因因果关系 | 改 vm.swappiness 后观察 24h 再改 dirty_ratio |
| 使用 cgroups v2 做资源隔离 | 防止单个应用耗尽主机资源影响其他服务 | systemd-run -p CPUQuota=50% -p MemoryMax=512M ... |
| 服务器设置 swappiness 为 10 | 仅在紧急情况下使用 swap,优先回收页面缓存 | /etc/sysctl.d/99-performance.conf 中写入 |
| 定期运行基准测试 | 跟踪性能趋势,及时发现硬件降级 | 每月运行一遍 sysbench CPU + fio 磁盘 + iperf3 网络 |
| 用 sar 保留历史数据 | 故障复盘需要"出事前"的指标作为对照基线 | sar -u -f /var/log/sysstat/sa$(date +%d -d yesterday) 回放昨日 CPU |
| 按业务类型选择 I/O 调度器 | 延迟敏感用 mq-deadline,吞吐优先用 none | 数据库盘 mq-deadline,NVMe 缓存盘 none |
练习题
- (概念)USE 方法论中的 U、S、E 分别代表什么?为什么 Saturation 比 Utilization 是更好的早期预警指标?
- (概念)火焰图的横轴和纵轴分别表示什么?如何快速定位 CPU 热点函数?
- (实操)在一台服务器上执行
mpstat -P ALL 1 5,记录每核的 %usr、%sys、%iowait、%idle。然后运行stress-ng --cpu 2 --timeout 30s,重新执行mpstat观察变化。解释为什么某些核的 %usr 升高而其他核不变。 - (实操)执行
free -h记录当前内存状态。设置vm.swappiness=10,运行stress-ng --vm 2 --vm-bytes 2G --timeout 30s,用vmstat 1 5观察 si/so 列。然后设置vm.swappiness=60重复实验,比较两个 swappiness 值下的 swap 活跃度差异。 - (🔍 挑战)对一台运行生产级应用(如 Nginx 或 MySQL)的服务器执行
perf record -F 99 -a -g -- sleep 30,生成火焰图。分析 top 5 最宽的函数的调用链,判断 CPU 主要消耗在哪个子系统(内核态/用户态、文件系统/网络栈/业务逻辑)。提出至少一条优化建议。
点击查看答案
- U=Utilization(利用率)、S=Saturation(饱和度)、E=Errors(错误)。Saturation 在 Utilization 到达 100% 前就开始增长(如 CPU 运行队列变长),因此是更早的预警信号。
- 横轴表示采样占比(越宽函数消耗 CPU 越多),纵轴表示调用栈(底部是被调函数,顶部是当前执行函数)。快速定位:找顶部最宽的方块,沿调用链向下看是哪个业务逻辑路径导致的。
- stress-ng 起 2 个 CPU worker,仅压满 2 个核,其他核的 %usr 基本不变。mpstat 可看到部分核 %usr 接近 100%,其余核保持较低 idle。
- swappiness=10 时 si/so 接近 0(很少 swap);swappiness=60 时同样压力下 si/so 明显增大。表明低 swappiness 更倾向回收缓存而非换出内存。
- perf record 采样后
perf report查看。若 top 5 宽函数在nginx: worker的epoll_wait中,说明 CPU 主要空闲等待 I/O;若在ssl_encrypt中,可考虑硬件加速或调整密码套件。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释系统性能指标和瓶颈分析方法 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成性能监控工具使用、参数调整 | 在终端实际执行 |
| 原理掌握 | 能说出 Linux 内核的进程调度、内存管理、IO 调度原理 | 画出流程图 |
| 故障排查 | 能独立排查 CPU 使用率高、内存不足、IO 性能差 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么需要为生产环境配置性能基线和监控告警 | 对比不同方案 |
本章总结
性能调优是 Linux 运维的高级技能,核心方法论是 "测量→分析→调整→验证"的闭环。USE(Utilization、Saturation、Errors)框架提供了系统性的资源瓶颈分析路径。CPU 调优用 mpstat + perf 火焰图,内存调优关注 available 列和 swap 使用,磁盘调优用 iostat 定位 %util 和 await,网络调优用 sar 统计带宽和重传。关键原则包括:建立基线、一次只改一个参数、用 cgroups 做资源隔离、用 stress-ng 做压力验证。
速查表
| 命令/参数 | 用途 |
|---|---|
mpstat -P ALL 1 | 每核 CPU 使用率 |
vmstat 1 5 | 内存和 CPU 概览(含 si/so) |
iostat -x 1 3 | 磁盘利用率 (%util) 和延迟 (await) |
sar -n DEV 1 3 | 网络接口带宽统计 |
perf record -F 99 -a -g -- sleep 30 | CPU 采样 30 秒 |
perf report --stdio | 查看采样报告 |
free -h | 查看内存(关注 available 列) |
vm.swappiness=10 | 减少 swap 使用倾向 |
stress-ng --cpu 4 --timeout 30s | CPU 压力测试 |
taskset -cp 0-3 PID | 绑定进程到指定 CPU 核心 |
学习路径建议
- 学完本章后建议阅读 5.12:eBPF 基础 eBPF 基础(下一代性能观测技术)
- 学完本章后建议阅读 4.7:压力测试实战 压力测试实战(在受控环境中验证瓶颈)
- 进阶可看 Brendan Gregg 的《性能之巅》和 Linux 内核文档
- 容器场景的性能隔离可参考 5.2:Docker 生产实践 Docker 生产实践中的资源限制部分
延伸阅读
- USE 方法论(Brendan Gregg)
- CPU 火焰图介绍
- FlameGraph 工具集
- perf-record 手册
- 推荐书籍:《性能之巅(第 2 版)》Brendan Gregg