内核追踪:ftrace、kprobe、uprobe、tracepoint 生产实战
某次生产故障:一个 Go 服务偶尔出现 200ms 的
fsync 延迟,但 prometheus-node-exporter
显示磁盘 I/O 正常,iostat 的 await
在 2ms 以内,strace 挂了 30
分钟没有捕捉到任何异常。最终通过 bpftrace 在
vfs_fsync_range 上挂
kprobe,发现延迟在特定时间点飙升——进一步分析是冷数据页
writeback(回写)在 fsync 前被强制触发。
这个案例说明:用户态可观测性工具能覆盖多数问题,但内核调度延迟、文件系统写回、网络栈丢包、内存回收等路径,只能在「内核算账」层面捕获。内核追踪不是日常工具;当 Metrics、Logs、Traces、Profile 都「正常」而用户仍报障时,它是工具箱里的最后一层。
本文聚焦 SRE 排障路径:如何用
ftrace、tracepoint、kprobe、uprobe、bpftrace
在可控开销下定位问题。eBPF 编程与 CO-RE
工程路径见 eBPF
可观测性全景;网络子系统 tracepoint 与
sk_buff 路径解剖见 Linux
网络子系统 · 内核网络追踪工具箱——本系列不重复
netfilter/tcp 栈源码级拆解。
实验环境说明(A
级,本机实测):WSL2,内核
6.6.87.2-microsoft-standard-WSL2,debugfs
已挂载于 /sys/kernel/debug(需 root)。下文
ftrace 与 tracepoint
命令在本环境执行过;bpftrace、perf、trace-cmd
未安装——相关片段标注为「需在具备 BTF 的
Linux 物理机/VM 上复现」,不伪造命令输出。
一、Linux 内核追踪技术栈全景
1.1 四条演进阶段
| 阶段 | 年代 | 里程碑 | 对 SRE 的意义 |
|---|---|---|---|
| ftrace 主线化 | 2008 | /sys/kernel/debug/tracing/ |
零依赖、伪文件系统控制 |
| perf_event | 2010–2015 | perf_event_open(2) |
PMU + 软件事件统一 |
| eBPF 扩展 | 2015–2020 | kprobe/uprobe 挂 BPF | 内核态过滤聚合 |
| CO-RE + BTF | 2020– | CONFIG_DEBUG_INFO_BTF |
bpftrace 跨版本读结构体 |
1.2 四层架构
| 层 | 组件 | 适合谁 | 典型开销 |
|---|---|---|---|
| 前端工具 | bpftrace, perf, trace-cmd, BCC | SRE | 取决于 attach 点 |
| 内核接口 | tracepoint, kprobe, uprobe, perf_event | 平台团队 | tracepoint 最低 |
| 数据管道 | eBPF ring buffer, ftrace buffer | 内核 | ring 溢出会丢事件 |
| 消费 | 直方图、火焰图、关联 Trace | 排障 | 取决于导出量 |
1.3 与 Metrics / Logs / Traces 的协作
内核追踪在 事故复盘剧本 链条中位于 Profile 之后:
flowchart LR
A[Alert] --> B[Metrics RED]
B --> C[Logs trace_id]
C --> D[Traces 慢 span]
D --> E[Profile 火焰图]
E --> F{用户态仍无法解释?}
F -->|是| G[ftrace / bpftrace]
F -->|否| H[变更关联 Events]
1.4 开销量级(文献与工程经验,非本环境 benchmark)
| attach 类型 | 单次命中量级 | 生产建议 | 来源 |
|---|---|---|---|
| tracepoint | ~50–200 ns | 可长期启用精选点 | Linux tracepoint 设计目标 |
| kprobe | ~100–300 ns | 仅低频函数、限时 | B. Gregg, BPF Performance Tools |
| uprobe | ~1–3 μs | 避免热路径 | 同上 |
| function_graph 全量 | 10–50× 劣化 | 禁止生产无过滤 | ftrace 文档警告 |
二、ftrace:内核自带的函数追踪器
2.1 debugfs 前置条件
ftrace 接口位于 debugfs,路径
/sys/kernel/debug/tracing/。
# 检查是否已挂载(WSL/部分云镜像默认未挂载)
mount | grep debugfs
# 若不存在,需 root 挂载
sudo mount -t debugfs none /sys/kernel/debug
# 验证 tracing 目录
ls /sys/kernel/debug/tracing/available_tracersWSL2 上普通用户访问会
Permission denied——文中所有 ftrace 操作均假设
sudo 或 CAP_SYS_ADMIN。
2.2 function tracer:按函数过滤
比 function_graph
更轻量,适合先看「哪些进程在调某个 syscall」:
cd /sys/kernel/debug/tracing
echo 0 > tracing_on
echo nop > current_tracer
echo "__x64_sys_read" > set_ftrace_filter
echo function > current_tracer
echo 1 > tracing_on
sleep 1
echo 0 > tracing_on
head -30 trace以下输出经删减,来自本环境 WSL2 实测:
# tracer: function
#
# entries-in-buffer/entries-written: 30/30 #P:24
#
# _-----=> irqs-off/BH-disabled
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / _-=> migrate-disable
# |||| / delay
# TASK-PID CPU# ||||| TIMESTAMP FUNCTION
# | | | ||||| | |
init-377 [006] ..... 2374.430358: __x64_sys_read <-x64_sys_call
sleep-14275 [014] ..... 2374.430369: __x64_sys_read <-x64_sys_call
sleep-14275 [014] ..... 2374.430535: __x64_sys_read <-x64_sys_call
node-1324 [023] ..... 2374.536801: __x64_sys_read <-x64_sys_call
containerd-721 [010] ..... 2374.794246: __x64_sys_read <-x64_sys_call
解读:TASK-PID 列显示调用方(如
node-1324、containerd-721);FUNCTION
列显示 __x64_sys_read <-x64_sys_call
表示从系统调用入口进入 read 实现。
2.3 function_graph tracer:调用链耗时
定位 write() / fsync()
内核路径上哪一步最慢:
cd /sys/kernel/debug/tracing
echo 0 > tracing_on
echo nop > current_tracer
echo > set_graph_function # 清空
echo "ext4_file_write_iter" > set_graph_function
echo function_graph > current_tracer
echo 1 > tracing_on
sleep 5
echo 0 > tracing_on
head -50 trace输出格式示例(结构说明,非本机 ext4 实测——WSL 默认文件系统可能为 ext4 或 9p,函数名因 FS 而异):
0) | __x64_sys_write() {
1) 0.421 us | security_file_permission();
2) 2.103 us | vfs_write();
3) | vfs_write() {
4) 8.552 us | ext4_file_write_iter();
5) | ext4_file_write_iter() {
6) 45.231 us | ext4_da_write_begin();
7) 12.004 us | ext4_da_write_end();
8) | }
9) | }
10) 0.312 us | }
数字列为该函数体内耗时(微秒)。ext4_da_write_begin
异常偏大时,结合 Continuous
Profiling 与块设备 tracepoint 继续下钻。
2.4 安全脚本:限时 + 自动恢复
#!/bin/bash
# ftrace-safe-capture.sh — 生产必备:超时自动关闭
set -euo pipefail
TRACING=/sys/kernel/debug/tracing
FUNC=${1:?usage: $0 <kernel_function>}
DURATION=${2:-30}
cleanup() {
echo 0 > "$TRACING/tracing_on" 2>/dev/null || true
echo nop > "$TRACING/current_tracer" 2>/dev/null || true
}
trap cleanup EXIT INT TERM
echo 0 > "$TRACING/tracing_on"
echo nop > "$TRACING/current_tracer"
echo "$FUNC" > "$TRACING/set_graph_function"
echo function_graph > "$TRACING/current_tracer"
echo 1 > "$TRACING/tracing_on"
sleep "$DURATION"
cat "$TRACING/trace" | head -5002.5 trace-cmd 与 KernelShark
trace-cmd 将 ftrace 采集封装为
trace.dat,KernelShark 提供 GUI 时间线。本 WSL
环境未安装 trace-cmd;在 Ubuntu 22.04+
物理机:
sudo apt install trace-cmd kernelshark
sudo trace-cmd record -e sched:sched_switch sleep 5
trace-cmd report2.6 ftrace histogram(无需 eBPF)
内核内置直方图触发器,适合 syscall 延迟分布:
# 示例:read syscall 延迟直方图(需内核支持 hist trigger)
echo "hist:keys=common_pid:vals=lat:sort=lat:lat=common_lat_us" > \
/sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger
sleep 10
cat /sys/kernel/debug/tracing/events/syscalls/sys_exit_read/hist
echo "!hist:keys=common_pid" > /sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger若 trigger 文件不存在,说明内核未启用对应
hist 支持——退而使用 bpftrace 或 perf。
三、tracepoint:内核的稳定 API
3.1 与 kprobe 的本质区别
| 维度 | tracepoint | kprobe |
|---|---|---|
| 稳定性 | 内核 ABI,跨版本字段布局稳定 | 函数名/签名可能变 |
| 语义 | 子系统作者定义的事件 | 任意函数,需读源码 |
| 开销 | 低 | 中 |
| 生产 | 首选 | 补充 |
3.2 浏览与启用
ls /sys/kernel/debug/tracing/events/sched/
cat /sys/kernel/debug/tracing/events/sched/sched_switch/formatsched_switch format 片段(本环境实测):
name: sched_switch
ID: 324
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:char prev_comm[16]; offset:8; size:16; signed:0;
field:pid_t prev_pid; offset:24; size:4; signed:1;
field:char next_comm[16]; offset:40; size:16; signed:0;
field:pid_t next_pid; offset:56; size:4; signed:1;
启用单个 CPU 上的 sched_switch:
echo 1 > /sys/kernel/debug/tracing/events/sched/sched_switch/enable
sleep 2
echo 0 > /sys/kernel/debug/tracing/events/sched/sched_switch/enable3.3 关键子系统 tracepoint 速查
| 子系统 | 事件 | 排障用途 |
|---|---|---|
| scheduler | sched_switch,
sched_wakeup |
CPU 饥饿、runqueue 延迟 |
| block | block_rq_issue,
block_rq_complete |
磁盘 I/O 延迟 |
| syscalls | sys_enter_*, sys_exit_* |
慢 syscall 分布 |
| ext4 | ext4_sync_file_enter |
fsync 路径 |
| tcp | tcp_retransmit_skb |
重传(网络细节见 linux-net 篇) |
3.4 用 ftrace 直接消费 tracepoint
cd /sys/kernel/debug/tracing
echo 0 > tracing_on
echo nop > current_tracer
echo 'sched:sched_switch' >> set_event
echo 1 > tracing_on
sleep 3
echo 0 > tracing_on
head -20 trace
echo > set_event # 清除3.5 bpftrace 挂 tracepoint(复现步骤,非本环境输出)
# 安装(Ubuntu 22.04+ 示例)
sudo apt install bpftrace linux-headers-$(uname -r)
# 块设备 I/O 延迟直方图
sudo bpftrace -e '
tracepoint:block:block_rq_issue { @start[args->dev] = nsecs; }
tracepoint:block:block_rq_complete {
$t = nsecs - @start[args->dev]; @lat_us = hist($t / 1000);
}' -d 10-d 10 表示 10 秒后自动退出并打印
map——生产安全必备。
四、kprobe:挂内核函数的动态探针
4.1 工作原理
x86 上用 int3
替换目标函数入口指令;命中后执行 BPF 程序或 ftrace
回调,再恢复原指令继续执行。
4.2 bpftrace 语法
sudo bpftrace -e 'kprobe:vfs_fsync_range { @start[tid] = nsecs; }
kretprobe:vfs_fsync_range /@start[tid]/ { @fsync_us = hist((nsecs - @start[tid]) / 1000); }' -d 304.3 生产安全边界
优先 tracepoint;kprobe 仅挂低频路径;禁止在
tcp_rcv_established、__schedule、_raw_spin_lock
等热路径长期挂载。
4.4 与 fentry/fexit 的选择
内核 ≥ 5.5 且目标函数支持时,eBPF 全景 推荐 fentry/fexit 替代 kprobe——开销约为一半。
4.5 版本差异
不同内核版本函数可能改名或内联;bpftrace -l 'kprobe:*write*'
列出可用符号后再挂。
五、uprobe:用户态函数的动态追踪
5.1 适用场景
遗留 C 服务无 metrics、追踪
malloc/free、OpenSSL
SSL_write 明文(HTTPS 可观测)。
5.2 容器路径问题
uprobe 需要宿主机上二进制绝对路径,如
/var/lib/docker/overlay2/<id>/merged/usr/bin/app。
5.3 Go 1.17+ 调用约定
寄存器传参导致 bpftrace 默认 arg0
读取失效;需查 Go 版本对应文档或使用 USDT。
5.4 USDT 优先
Python python:function__entry、MySQL
mysql:query__start 等比盲目 uprobe 更稳定。
5.5 示例
sudo bpftrace -e 'uprobe:/usr/lib/x86_64-linux-gnu/libc.so.6:malloc { @bytes = hist(arg1); }' -d 15六、bpftrace:内核追踪的高级语言
6.1 一分钟上手
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }' -d 56.2 内置变量
pid, tid, uid,
comm, nsecs, cpu,
arg0–arg3(架构相关)。
6.3 Map 类型
@count[key], @hist(val),
@dist[key]——内核态聚合,减少 ring buffer
压力。
6.4 生产模板
始终 -d duration;按
pid/comm 过滤;输出量过大时改用
@count 而非 printf。
6.5 BTF 依赖
CONFIG_DEBUG_INFO_BTF=y;缺失时
bpftrace 无法解析 args->
结构体字段。检查:ls /sys/kernel/btf/vmlinux。
七、perf 与持续剖析产品
7.1 perf 定位
正式性能采集、火焰图、perf stat
硬件计数;bpftrace 适合 ad-hoc 探索。
7.2 常用命令
sudo perf top
sudo perf record -g -p $(pidof myapp) sleep 30
sudo perf script | stackcollapse-perf.pl | flamegraph.pl > out.svg7.3 与 Parca/Pixie
Continuous Profiling 用 eBPF 持续采样;手工 bpftrace 用于事故窗口临时加深。
7.4 K8s DaemonSet 权限
最小权能:CAP_BPF, CAP_PERFMON,
CAP_SYS_ADMIN(部分内核仅需前两者)——避免
privileged: true。
八、内核追踪的生产安全模型
8.1 限时三件套
timeout、bpftrace -d、trap cleanup
脚本。
8.2 白名单 attach 点
平台团队维护允许的 tracepoint/kprobe 列表;on-call 只能跑白名单脚本。
8.3 ring buffer 溢出
事件丢失时 bpftrace 打印
Lost N events——需减小 printf
或加强过滤。
8.4 变更窗口
内核追踪视为变更:需工单、on-call 值守、可回滚。
8.5 审计
记录谁在哪个节点跑了什么脚本、持续多久——与 Events 变更关联 对齐。
九、决策树与工具选择
9.1 快速决策
| 问题 | 工具 |
|---|---|
| 哪类内核事件发生了? | tracepoint |
| 某内核函数多慢? | kprobe + hist |
| 用户态库函数? | uprobe/USDT |
| 快速探索? | bpftrace |
| 正式火焰图? | perf |
| 持续剖析? | Parca/Pixie |
9.2 与 strace 对比
strace 用 ptrace,开销数量级更高;仅适合短窗口单进程,不适合生产。
9.3 与网络篇边界
TCP 重传根因、kfree_skb reason 枚举见 linux-net
追踪工具箱;本篇只引用 tcp_retransmit_skb
作为「该看内核了」的信号。
十、工程坑点
10.1 function_graph 无过滤
全内核函数追踪 → 节点不可用,真实事故模式。
10.2 kprobe 挂不可重入函数
特定锁路径可能导致死锁——仅短时、低频。
10.3 容器内 uprobe 路径错误
挂容器内路径失败;必须解析 overlay 合并层路径。
10.4 WSL debugfs 权限
普通用户无法访问;且部分 tracing 特性在虚拟化内核上受限。
10.5 BTF 缺失
发行版 linux-image-generic 无 BTF 包时需装
linux-image-$(uname -r)-dbgsym。
10.6 追踪忘记关闭
交班 checklist 必须含
cat /sys/kernel/debug/tracing/tracing_on 应为
0。
十一、落地清单
11.1 平台能力
11.2 on-call
11.3 合规
十二、与 eBPF 全景和 linux-net 的阅读边界
12.1 本系列覆盖
SRE 排障:何时下钻内核、用哪种 attach、如何控风险、如何与 Metrics/Logs/Traces 串联。
12.2 14 篇覆盖
bcc/bpftrace/libbpf 工程路径、CO-RE、verifier、Pixie/DeepFlow 产品化。
12.3 linux-net 覆盖
网络 tracepoint
字段、skb_drop_reason、per-function
网络火焰图。
12.4 15 篇覆盖
用户态网络可观测:eBPF flow、Service Mesh、DNS——不替代内核 syscall 延迟分析。
十三、关键概念回顾
| 概念 | 一句话 |
|---|---|
| ftrace | 内核自带,function_graph
看调用链耗时;必须过滤+限时 |
| tracepoint | 稳定 ABI,生产首选 |
| kprobe | 动态挂内核函数,能力大风险大 |
| uprobe | 用户态断点,注意容器路径 |
| bpftrace | 类 awk 的 eBPF 脚本,-d 限时 |
十四、常见误解
| 误解 | 事实 |
|---|---|
| 内核追踪日常开着就行 | 必须按需、限时;常态用 Metrics+Profile |
| bpftrace 可以替代 eBPF 工程 | 产品化、CO-RE、长期运行用 libbpf |
| strace 够用了 | ptrace 开销太大,生产仅短窗口 |
| 网络问题本篇讲完 | TCP 路径见 linux-net 23 篇 |
十五、下一步
内核追踪是 eBPF 与内核部分的收束篇。治理层从 SLO 工程 开始。排障全链路见 事故复盘剧本。
附录 A:WSL2 复现 checklist
sudo mount -t debugfs none /sys/kernel/debug- 验证
available_tracers含function_graph - ftrace 过滤脚本跑通(§2.2 实测输出)
- 安装
bpftrace:
sudo apt install bpftrace(可选,物理机推荐) - 检查 BTF:
ls /sys/kernel/btf/vmlinux
附录 B:sched_switch 延迟分析思路
高 sched_switch 频率 + 单进程
comm 长时间不运行 → CPU 竞争或 cgroup CPU
限流。 结合 cgroup v2 cpu.max 与 Metrics 中
container_cpu_cfs_throttled_seconds_total。 bpftrace
模板:tracepoint:sched:sched_wakeup 与
sched_switch 配对算 runqueue 延迟。
附录 C:块设备延迟与 iostat 对照
iostat -x 的 await
是聚合值;tracepoint 可看 per-device、per-process。 当
await 正常但应用 fsync 慢 → 查 ext4
writeback、journal 提交路径。
附录 D:文件系统 fsync 剧本
- Metrics:节点 disk write 吞吐正常?
- Trace:ext4_sync_file_enter/exit 延迟
- kprobe:vfs_fsync_range kretprobe hist
- 若 writeback → 查 dirty_ratio、 cgroup memory 压力
参考资料
- Linux Kernel, Documentation/trace/ftrace.rst
- Linux Kernel, Documentation/trace/tracepoints.rst
- B. Gregg, BPF Performance Tools, Addison-Wesley, 2019
- bpftrace Reference Guide, https://github.com/bpftrace/bpftrace/blob/master/docs/reference_guide.md
- man perf_event_open(2), https://man7.org/linux/man-pages/man2/perf_event_open.2.html
- 本站 eBPF 可观测性全景
- 本站 linux-net 内核网络追踪工具箱
- 本站 Continuous Profiling
- 本站 Profiling
- 本站 网络可观测性
上一篇:Continuous Profiling:持续剖析架构与落地
下一篇:SLO 工程:错误预算、Burn Rate、多窗口多燃烧率告警
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【可观测性工程】eBPF 可观测性全景:bcc、bpftrace、libbpf 的工程路径
eBPF 如何实现零侵入、内核级、低开销的可观测性:从 kprobe/uprobe/tracepoint/fentry 钩子机制,到 bcc 工具集、bpftrace 脚本语言、libbpf+CO-RE 可移植编程,再到 Pixie、DeepFlow、Grafana Beyla 等商业化工具,结合内核版本兼容性与生产部署实战。
【可观测性工程】网络可观测性:Cilium Hubble、Pixie、DeepFlow、Tetragon
从 L3/L4/L7 三层观测视角出发,讲 eBPF socket filter / tc / XDP 数据采集与 Cilium Hubble 流日志、Tetragon 安全可观测、Pixie 协议自动解析、DeepFlow 架构;展开 bpftrace + kfree_skb_reason 的内核丢包定位、TLS 解密、HTTP/2 解析与服务拓扑自动发现。
可观测性工程
从 Metrics、Logs、Traces 到 Profiling、eBPF、OpenTelemetry 与 SLO 治理,面向中国工程团队的可观测性系统化手册。全 25 篇。
【可观测性工程】Traces 栈与采样:Jaeger、Tempo、Zipkin、SkyWalking
拆解 Jaeger、Tempo、SkyWalking 架构差异与采样策略(头部/尾部/自适应),给出 W3C TraceContext 传播、OpenTelemetry tail_sampling 配置与选型框架。