土法炼钢 · 系统与基础设施

【可观测性工程】内核追踪:ftrace、kprobe、uprobe、tracepoint 生产实战

文章导航

分类入口
architectureobservability
标签入口
#kernel#ftrace#kprobe#uprobe#tracepoint#bpftrace#perf#ebpf#linux#tracing#debugfs

目录

内核追踪:ftrace、kprobe、uprobe、tracepoint 生产实战

某次生产故障:一个 Go 服务偶尔出现 200ms 的 fsync 延迟,但 prometheus-node-exporter 显示磁盘 I/O 正常,iostatawait 在 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 栈源码级拆解

Linux 内核追踪技术栈分层

实验环境说明(A 级,本机实测):WSL2,内核 6.6.87.2-microsoft-standard-WSL2debugfs 已挂载于 /sys/kernel/debug(需 root)。下文 ftrace 与 tracepoint 命令在本环境执行过;bpftraceperftrace-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_tracers

WSL2 上普通用户访问会 Permission denied——文中所有 ftrace 操作均假设 sudoCAP_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-1324containerd-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 -500

2.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 report

2.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/format

sched_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/enable

3.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 30

4.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 5

6.2 内置变量

pid, tid, uid, comm, nsecs, cpu, arg0arg3(架构相关)。

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.svg

7.3 与 Parca/Pixie

Continuous Profiling 用 eBPF 持续采样;手工 bpftrace 用于事故窗口临时加深。

7.4 K8s DaemonSet 权限

最小权能:CAP_BPF, CAP_PERFMON, CAP_SYS_ADMIN(部分内核仅需前两者)——避免 privileged: true

八、内核追踪的生产安全模型

8.1 限时三件套

timeoutbpftrace -dtrap 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

  1. sudo mount -t debugfs none /sys/kernel/debug
  2. 验证 available_tracersfunction_graph
  3. ftrace 过滤脚本跑通(§2.2 实测输出)
  4. 安装 bpftrace:sudo apt install bpftrace(可选,物理机推荐)
  5. 检查 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_wakeupsched_switch 配对算 runqueue 延迟。

附录 C:块设备延迟与 iostat 对照

iostat -xawait 是聚合值;tracepoint 可看 per-device、per-process。 当 await 正常但应用 fsync 慢 → 查 ext4 writeback、journal 提交路径。

附录 D:文件系统 fsync 剧本

  1. Metrics:节点 disk write 吞吐正常?
  2. Trace:ext4_sync_file_enter/exit 延迟
  3. kprobe:vfs_fsync_range kretprobe hist
  4. 若 writeback → 查 dirty_ratio、 cgroup memory 压力

参考资料

  1. Linux Kernel, Documentation/trace/ftrace.rst
  2. Linux Kernel, Documentation/trace/tracepoints.rst
  3. B. Gregg, BPF Performance Tools, Addison-Wesley, 2019
  4. bpftrace Reference Guide, https://github.com/bpftrace/bpftrace/blob/master/docs/reference_guide.md
  5. man perf_event_open(2), https://man7.org/linux/man-pages/man2/perf_event_open.2.html
  6. 本站 eBPF 可观测性全景
  7. 本站 linux-net 内核网络追踪工具箱
  8. 本站 Continuous Profiling
  9. 本站 Profiling
  10. 本站 网络可观测性

上一篇Continuous Profiling:持续剖析架构与落地

下一篇SLO 工程:错误预算、Burn Rate、多窗口多燃烧率告警

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。

2026-04-22 · architecture / observability

可观测性工程

从 Metrics、Logs、Traces 到 Profiling、eBPF、OpenTelemetry 与 SLO 治理,面向中国工程团队的可观测性系统化手册。全 25 篇。


By .