Linux 性能调优与追踪完整篇:ftrace、perf、eBPF从采样到落地验证

CPU 被打满却说不清热点、延迟尖刺只能「重启试一下」、上线后回归全靠猜------缺的不是参数列表,而是 可复现的观测路径 :从 tracepoint/kprobe 到采样火焰图,再到改参与回归对比。本文把 ftrace、perf_event、eBPF/bpftrace、常见调优开关与排障顺序合成一篇闭环。


源码锚点

路径 作用
kernel/trace/ftrace.c ftrace 核心、function tracer
kernel/trace/trace.c tracefs 环形缓冲与输出
include/linux/ftrace.h ftrace API
kernel/events/core.c perf_event 子系统
kernel/kprobes.c kprobe 动态插桩
kernel/bpf/ eBPF 验证器、地图、运行时
kernel/trace/bpf_trace.c BPF 与 tracing 衔接
fs/tracefs/ / debugfs 用户态控制面(挂载点因发行版而异)
tools/perf/ 用户态 perf 工具
Documentation/trace/、Documentation/bpf/ 官方追踪与 BPF 文档

ftrace 控制面(示意):

bash 复制代码
# 通常需要 root;路径可能是 /sys/kernel/tracing
mount | grep tracefs
cd /sys/kernel/tracing
echo function > current_tracer
echo do_sys_openat2 > set_ftrace_filter   # 示例符号以本机为准
echo 1 > tracing_on
cat trace | head
echo 0 > tracing_on

perf 采样骨架:

bash 复制代码
perf record -F 99 -g -- ./app
perf report
# 或系统范围
perf top
perf record -a -g -- sleep 10

调用链

观测数据从内核到用户态

#mermaid-svg-VUehsEsGWDM6kxoH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VUehsEsGWDM6kxoH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VUehsEsGWDM6kxoH .error-icon{fill:#552222;}#mermaid-svg-VUehsEsGWDM6kxoH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VUehsEsGWDM6kxoH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH .marker.cross{stroke:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VUehsEsGWDM6kxoH p{margin:0;}#mermaid-svg-VUehsEsGWDM6kxoH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster-label text{fill:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster-label span{color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster-label span p{background-color:transparent;}#mermaid-svg-VUehsEsGWDM6kxoH .label text,#mermaid-svg-VUehsEsGWDM6kxoH span{fill:#333;color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .node rect,#mermaid-svg-VUehsEsGWDM6kxoH .node circle,#mermaid-svg-VUehsEsGWDM6kxoH .node ellipse,#mermaid-svg-VUehsEsGWDM6kxoH .node polygon,#mermaid-svg-VUehsEsGWDM6kxoH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .rough-node .label text,#mermaid-svg-VUehsEsGWDM6kxoH .node .label text,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape .label,#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape .label{text-anchor:middle;}#mermaid-svg-VUehsEsGWDM6kxoH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .rough-node .label,#mermaid-svg-VUehsEsGWDM6kxoH .node .label,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape .label,#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape .label{text-align:center;}#mermaid-svg-VUehsEsGWDM6kxoH .node.clickable{cursor:pointer;}#mermaid-svg-VUehsEsGWDM6kxoH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH .arrowheadPath{fill:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VUehsEsGWDM6kxoH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VUehsEsGWDM6kxoH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VUehsEsGWDM6kxoH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VUehsEsGWDM6kxoH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VUehsEsGWDM6kxoH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VUehsEsGWDM6kxoH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster text{fill:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster span{color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VUehsEsGWDM6kxoH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VUehsEsGWDM6kxoH rect.text{fill:none;stroke-width:0;}#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape p,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape .label rect,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VUehsEsGWDM6kxoH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VUehsEsGWDM6kxoH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VUehsEsGWDM6kxoH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 静态
动态函数
PMU 采样
可编程
感兴趣事件
观测手段
tracepoint
kprobe / ftrace filter
perf_event
eBPF 程序
ring buffer / perf mmap
BPF map / ringbuf
用户态工具读取
报告 / 火焰图 / 指标

调优闭环分层

#mermaid-svg-hqHuOnUWouyZb6O2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hqHuOnUWouyZb6O2 .error-icon{fill:#552222;}#mermaid-svg-hqHuOnUWouyZb6O2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hqHuOnUWouyZb6O2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 .marker.cross{stroke:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hqHuOnUWouyZb6O2 p{margin:0;}#mermaid-svg-hqHuOnUWouyZb6O2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster-label text{fill:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster-label span{color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster-label span p{background-color:transparent;}#mermaid-svg-hqHuOnUWouyZb6O2 .label text,#mermaid-svg-hqHuOnUWouyZb6O2 span{fill:#333;color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .node rect,#mermaid-svg-hqHuOnUWouyZb6O2 .node circle,#mermaid-svg-hqHuOnUWouyZb6O2 .node ellipse,#mermaid-svg-hqHuOnUWouyZb6O2 .node polygon,#mermaid-svg-hqHuOnUWouyZb6O2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .rough-node .label text,#mermaid-svg-hqHuOnUWouyZb6O2 .node .label text,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape .label,#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-hqHuOnUWouyZb6O2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .rough-node .label,#mermaid-svg-hqHuOnUWouyZb6O2 .node .label,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape .label,#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape .label{text-align:center;}#mermaid-svg-hqHuOnUWouyZb6O2 .node.clickable{cursor:pointer;}#mermaid-svg-hqHuOnUWouyZb6O2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 .arrowheadPath{fill:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hqHuOnUWouyZb6O2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hqHuOnUWouyZb6O2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hqHuOnUWouyZb6O2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hqHuOnUWouyZb6O2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hqHuOnUWouyZb6O2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster text{fill:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster span{color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hqHuOnUWouyZb6O2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape p,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape .label rect,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hqHuOnUWouyZb6O2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hqHuOnUWouyZb6O2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hqHuOnUWouyZb6O2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 验证
假设与改动
观测
定义问题
延迟? CPU? IO? 唤醒?
建立 baseline
perf / top / iostat
ftrace / trace-cmd
bpftrace / BCC
调度/内存/IO/驱动参数
代码热点修复
同负载复测
回滚开关


重点知识

1. 先定性,再选工具

症状 先看 深挖
CPU 高 perf top/record -g 符号、锁、软中断
延迟尖刺 cyclictest、调度/中断追踪 irqsoff/preemptirqsoff、唤醒链
IO 等 iostat、perf block 事件 电梯、队列深度、FS 回写
内存 /proc/meminfo、psi reclaim、oom、cgroup 限制

没有 baseline(同负载下的延迟/CPU/带宽数字)就改 sysctl,属于盲调。

2. ftrace:低成本看清调用与关闭抢占

  • function / function_graph:看谁调用谁、耗时轮廓。
  • irqsoff / preemptoff:关中断/关抢占过久(驱动里常见)。
  • sched / wakeup:任务为何睡、被谁唤醒。
bash 复制代码
trace-cmd record -e sched:sched_switch -e sched:sched_wakeup sleep 5
trace-cmd report | head

注意:过滤不当时开销与 trace 体积会爆;生产先短时、窄 filter。

3. perf:PMU 采样与火焰图

perf_event 把硬件计数器/软件事件接到统一接口;perf record 采样调用栈,适合「CPU 花在哪」。

bash 复制代码
# 权限相关
sysctl kernel.perf_event_paranoid
# 常见:cache-misses、cycles、page-faults
perf stat -e cycles,cache-misses,page-faults -- ./app

解读要点:采样有偏差;内联/缺符号会「糊」;先保证 vmlinux/debuginfod 或至少 kallsyms 可读。

4. eBPF:验证后可编程观测

流程:编写(或 bpftrace 一行)→ verifier 保证安全 → 加载 → 挂到 kprobe/tracepoint/XDP 等 → map/ringbuf 汇总。

bash 复制代码
# 示例:统计 syscall 次数(语法随 bpftrace 版本微调)
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'

约束:

  • 无 verifier 通过则无法加载------这是特性不是障碍;
  • 生产控制 attach 范围与采样率,避免自扰动;
  • 权限:通常需要 CAP_BPF/CAP_PERFMON 或 root(视内核与发行版)。

5. kprobe 与开销意识

kprobe 可动态插到几乎任意内核函数,但:

  • 热路径高频命中会显著扰动;
  • 部分函数不可探测或随版本改名;
  • 优先用稳定 tracepoint,kprobe 作补充。

6. 配置与安全

bash 复制代码
# 追踪文件系统
mount -t tracefs tracefs /sys/kernel/tracing
# BPF 文件系统(部分工具需要)
mount -t bpf bpf /sys/fs/bpf
项 说明
kernel.perf_event_paranoid 控制非特权 perf 能力
debugfs/tracefs 权限 避免无关用户读内核地址信息
生产追踪 限时、限事件、有回滚

7. 从观测到改参:几类高频旋钮(先测后改)

领域 示例入口 说明
调度 schedutil、CPU 亲和、nice/cgroup cpu 先确认是否真 CPU 饱和
内存 vm.swappiness、vfs_cache_pressure、cgroup 限制 配合 PSI/meminfo
网络 somaxconn、队列、NAPI/中断开销 先 ss/perf 再改
块 IO 调度器、队列深度、ionice 先分清读/写/刷新
驱动 线程化 IRQ、合并工作、避免关中断过久 用 irqsoff 验证

原则:一次只改一类变量 ,保留开关与回滚命令。容器/ cgroup 场景下,宿主机 sysctl 与容器限额要分开看。

8. 常见坑

坑 结果 处理
无符号表 火焰图全是地址 安装 debug 包 / 带 vmlinux
同时开太多 tracer 机器变慢、数据失真 单次一种目的
只调参不复测 「好像好了」 固定负载脚本对比
把平均当尾延迟 P99 仍炸 看直方图/百分位
在生产长期开 function tracer 吞吐断崖 限时、窄 filter、事后关闭

Checklist

  • 调优前有书面 baseline(负载描述 + 关键指标)
  • 能说明 ftrace / perf / eBPF 各自擅长的问题类型
  • 会用 perf record -g + report 定位用户/内核热点
  • 会在 tracefs 上做一次窄过滤的 function 追踪并关闭
  • 优先选用 tracepoint,明白 kprobe 的开销与版本风险
  • 知道 perf_event_paranoid 与 tracefs 挂载对工具的影响
  • 每次改动可回滚,并用同一负载复测验证

小结

内核已经把观测做成可组合管线:事件源 → 缓冲/映射 → 用户态分析。调优的设计意图不是堆参数,而是用 ftrace/perf/eBPF 把假设证伪或证实。顺序固定为:定性 → 选工具 → 短时窄范围采集 → 改一处 → 对比 baseline。

相关推荐
未济3 天前
linux 配置环境变量
linux
傲世仙尊3 天前
目录即文件-Ext文件系统收尾篇
linux·c语言
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
_艾伦 耶格尔.3 天前
进程间通信
linux
AI职业加油站3 天前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
Liuqy-053 天前
Linux IO编程——静态库、动态库
linux
此冬歌咏3 天前
K8s 节点故障实战:优雅驱逐 31 秒,硬故障 331 秒,以及那个永远 Pending 的 Pod
运维·k8s
彧azz3 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
-梅3 天前
linux(8) 软硬链接
linux·运维·服务器
Wang's Blog3 天前
Java 项目实战: 外卖平台-文件下载与ServletOutputStream回写浏览器
服务器·项目开发