bpftrace

张开发
2026/4/11 15:45:14 15 分钟阅读

分享文章

bpftrace
bpftrace是 Linux 下一款基于eBPF技术的高级跟踪语言与运行时工具以简洁的类 AWK/C 语法提供内核与用户态的动态、低开销、安全跟踪能力是性能分析、故障排查与系统观测的利器核心特性基于 eBPF无需修改源码 / 加载模块代码经内核验证器安全执行。语法简洁探针 /过滤器/ { 动作 }易写易读。多探针类型kprobe/kretprobe内核函数入口 / 返回tracepoint内核静态跟踪点稳定 APIuprobe/uretprobe用户态函数跟踪profile定时采样CPU 占用、内核栈内置变量pid/tid/comm/nsecs/kstack/arg0~argN/retval内置函数printf()/count()/hist()/lhist()/str()/delete()Map 聚合key value实现统计、直方图、时间序等安装主流发行版# Ubuntu/Debian sudo apt install bpftrace # Fedora/RHEL sudo dnf install bpftrace # Arch sudo pacman -S bpftrace基本语法bpftrace [,probe,...] /filter/ { action; }probe触发点如kprobe:vfs_readfilter可选条件如/pid 1234/action触发时执行逻辑完整参数清单参数作用-e CODE执行单行 bpftrace 代码-l [PROBE]列出可用探针支持通配符-lv [PROBE]列出探针 详细参数结构体-p PID绑定跟踪指定进程-c CMD跟踪命令从启动到结束-vverbose 详细输出-qquiet 精简输出-V查看版本-d语法检查不运行-o FILE输出重定向到文件--unsafe允许不安全操作常用命令与单行示例1. 查看可用探针bpftrace -l # 全部 bpftrace -l *vfs* # 含 vfs bpftrace -l tracepoint:syscalls:sys_enter_* # 系统调用入口2. Hello Worldbpftrace -e BEGIN { printf(Hello bpftrace\n); }3. 按进程统计系统调用bpftrace -e tracepoint:raw_syscalls:sys_enter { [comm] count(); }4. 跟踪文件打开进程名 路径bpftrace -e tracepoint:syscalls:sys_enter_openat { printf(%-8s %s\n, comm, str(args-filename)); }5. 跟踪指定 PID 打开文件bpftrace -e tracepoint:syscalls:sys_enter_openat /pid 1234/ { printf(%s - %s\n, comm, str(args-filename)); }6. 统计vfs_read耗时直方图bpftrace -e kprobe:vfs_read { start[tid] nsecs; } kretprobe:vfs_read /start[tid]/ { latency hist(nsecs - start[tid]); delete(start[tid]); }7. 内核栈采样CPU 热点bpftrace -e profile:hz:99 { [kstack] count(); }8. 块 I/O 大小分布bpftrace -e tracepoint:block:block_rq_issue { size hist(args-bytes); }9. 谁在执行 open打印进程 文件名bpftrace -e tracepoint:syscalls:sys_enter_openat { printf(%-6d %-10s %s\n, pid, comm, str(args-filename); }10. 跟踪进程创建bpftrace -e tracepoint:sched:sched_process_fork { printf(fork: %d - %d\n, args-parent_pid, args-child_pid); }11. 跟踪进程退出bpftrace -e tracepoint:sched:sched_process_exit { printf(exit: %d %s\n, pid, comm); }bpftrace 语言bpftrace 是一门专门为跟踪设计的脚本语言语法借鉴了 C AWK但编译后运行的是 eBPF 字节码不是 C 代码也不编译成二进制。bpftrace 借用了 C 的表面语法所以看起来很像变量$a 1;结构体args-filename打印printf(%d %s, pid, comm);运算符!||注释///* */但这只是 “长得像”不是 C。关键区别特性C 语言bpftrace 语言类型强类型必须声明弱类型不用声明编译编译成可执行文件编译成eBPF 字节码运行直接运行程序在内核 eBPF 虚拟机运行函数可自定义函数不能自定义函数循环支持 for/while几乎不支持循环eBPF 限制指针自由操作严格限制不能乱指用途写软件、系统、应用专门做跟踪、观测、性能分析最核心区别C 是通用编程语言bpftrace 是跟踪领域专用 DSL领域专用语言它真正的血缘C AWKbpftrace 语法 C 风格AWK 模型AWK 模型模式 { 动作 }bpftrace 模型探针 /过滤条件/ { 动作 }这才是它的本质。bpftrace 代码规范Map 命名必须小写 下划线见名知意前缀建议 动作 / 目标 类型read_count # 计数 read_latency # 延迟 start_time[tid] # 线程起始时间 file_bytes # 字节统计变量命名局部变量$ 小写下划线$pid pid; $ts nsecs; $path str(args-filename);脚本文件名小写、下划线、.bt后缀含义清晰tcp_lat.btopensnoop.btdisk_hist.bt结构规范固定模板所有 bpftrace 脚本强制三段式#!/usr/bin/env bpftrace /* * 功能XXX跟踪工具 * 作者XXX * 用途XXX */ BEGIN { printf(Tracing... CtrlC to stop\n); printf(%-8s %-12s %s\n, PID, COMM, PATH); } // 探针逻辑 tracepoint:syscalls:sys_enter_openat { printf(%-8d %-12s %s\n, pid, comm, str(args-filename)); } END { printf(\nTracing done.\n); }脚本文件.bt示例opensnoop.bt#!/usr/bin/env bpftrace tracepoint:syscalls:sys_enter_openat { printf(%-6d %-12s %s\n, pid, comm, str(args-filename)); }运行sudo bpftrace opensnoop.bt常用内置变量pid进程 IDtid线程 IDcomm进程名nsecs当前时间纳秒kstack/ustack内核 / 用户栈arg0~argNkprobe 参数retvalkretprobe 返回值argstracepoint 参数结构体bpftrace-e 单行命令结构固定格式黄金格式探针 /过滤条件/ { 动作; }顺序不能变探针 → 过滤 → 动作过滤必须写在探针后不要写在 {} 里错误kprobe:vfs_read { if (pid 1234) { ... } }正确kprobe:vfs_read /pid 1234/ { ... }原因过滤器在内核态提前过滤性能提升 10~100 倍必须排除 pid 0生产规范跟踪系统调用 / 内核函数时一定要排除内核线程/pid ! 0/示例bpftrace -e tracepoint:syscalls:sys_enter_openat /pid ! 0/ { ... }字符串必须判空防崩溃str()不能传 0否则直接崩溃。正确写法args-filename ? str(args-filename) : null统计类必须用 map不要打印刷屏错误刷屏卡死tracepoint:syscalls:sys_enter_read { printf(...); }正确聚合统计安全tracepoint:syscalls:sys_enter_read { [comm] count(); }延迟统计必须用 tid不能用 pid错误start[pid] nsecs;正确start[tid] nsecs;多线程进程用 pid 会覆盖导致数据错乱。kretprobe 必须判断 key 存在防止内存泄漏、报错kretprobe:vfs_read /start[tid]/ { ... }单行代码风格规范空格统一/pid 123/两侧空格不写复杂逻辑不嵌套能用 count ()/hist () 就不用 printf探针名简短清晰vfs_read不写SyS_read等别名适用场景性能分析CPU / 内存 / 磁盘 I/O/ 网络延迟、热点函数故障排查进程异常、文件句柄泄漏、系统调用错误安全观测可疑进程 / 系统调用 / 文件访问应用调试用户态库 / 二进制跟踪uprobe优势对比比 BCC 轻量单行 / 短脚本更高效比 SystemTap/DTrace原生 eBPF、低开销、无需编译比 ftrace/perf语法更简洁、聚合更强

更多文章