eBPF 允许在内核里跑沙箱化的小程序,无侵入地观察系统行为。
bpftrace 是 awk 风格的高级语言,让你不用 C / libbcc 也能写 eBPF
脚本。一行就能解决很多用 strace / perf 都麻烦的问题。
装
sudo apt install -y bpftrace
bpftrace --version # 需要 >= 0.16,老版本功能少很多
# 内核 5.5+ / Debian 11+ / Ubuntu 20.04+
1. 一行解决的常见问题
谁在打开 /etc/passwd
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_openat
/str(args->filename) == "/etc/passwd"/
{ printf("%s (%d) opened /etc/passwd\n", comm, pid); }
'
任何进程 open /etc/passwd 时立即打印进程名 + PID。
哪个进程在创建 socket
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_socket
{ printf("%s (%d) opened socket family=%d type=%d\n",
comm, pid, args->family, args->type); }
'
哪个 exec 系列 syscall 在被频繁调用
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_execve
{ printf("%s -> %s\n", comm, str(args->filename)); }
'
实时显示所有 exec —— 找出 shell 死循环 / 短生命周期进程喷。
系统调用直方图
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_read
{ @[comm] = count(); }
interval:s:5 { print(@); clear(@); exit(); }
'
# 5 秒内每个进程的 read 次数
哪个进程在 page fault
sudo bpftrace -e '
software:major-faults:1
{ @[comm] = count(); }
'
# Ctrl-C 后看汇总
major-fault = 必须从磁盘加载 page,对应 swap / mmap miss 等慢操作。
2. 用户态 dynamic instrumentation (uprobe)
观察 nginx 调用某函数:
# 列 nginx 二进制的可探测函数
sudo bpftrace -l 'uprobe:/usr/sbin/nginx:*' | head
# 探测某个函数
sudo bpftrace -e '
uprobe:/usr/sbin/nginx:ngx_http_process_request
{ @[comm] = count(); }
'
不需要重启 nginx、不需要改代码,实时统计某函数被调多少次。
3. 时延直方图
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_read
{ @start[tid] = nsecs; }
tracepoint:syscalls:sys_exit_read
/@start[tid]/
{ @us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }
interval:s:5 { print(@us); clear(@us); }
'
输出每 5 秒一次 read syscall 的时延直方图(微秒):
@us:
[0] 8 |@ |
[1] 256 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
[2, 4) 384 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
[4, 8) 128 |@@@@@@@@@@@@@@@@ |
[8, 16) 16 |@@ |
[16, 32) 4 | |
[1K, 2K) 1 | |
立刻看出 read 大多 1-4 µs,偶尔有 1-2 ms 的慢——可能是磁盘 / 网络 IO
慢。
4. 内置变量速查
pid/tid:进程 / 线程 IDcomm:进程名(前 16 字符)nsecs:当前时间戳(纳秒)cpu:当前 CPUargs:tracepoint 参数(结构体)kstack/ustack:内核 / 用户调用栈
5. 输出 + 聚合
@hist_name = hist(value) # 2 的幂直方图
@lhist_name = lhist(value, 0, 100, 10) # 线性直方图
@count[key] = count() # 计数
@sum[key] = sum(value) # 求和
@avg[key] = avg(value) # 平均
@stats[key] = stats(value) # min/max/avg/count/sum
@top10 = bottom(10, count()) # Top-N
Map 自动按 key 分组。
6. 实战:找出"哪个文件被读最多"
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_openat
{ @opens[str(args->filename)] = count(); }
interval:s:30
{ print(@opens, 10); clear(@opens); }
'
# 每 30 秒输出 Top 10 被 open 的文件
7. 现成脚本库:bpftrace tools
git clone https://github.com/iovisor/bpftrace
ls bpftrace/tools
# biolatency.bt biosnoop.bt execsnoop.bt funcslower.bt
# opensnoop.bt runqlat.bt tcpaccept.bt tcpconnect.bt
# ...
例:磁盘 IO 时延直方图
sudo bpftrace bpftrace/tools/biolatency.bt
execsnoop.bt 实时显示新建进程,tcpconnect.bt 显示所有新建 TCP 连接,
都是诊断生产问题的利器。
8. 跟 bcc 比
bcc 是用 C 写 eBPF + Python 包装,更强大但学习成本高。
bpftrace 是高级语言,限制更多但写起来快 10x。生产经验:
- 简单监控 / 调试一次性脚本:bpftrace
- 持续运行的复杂 agent / 工具:bcc
9. 性能影响
bpftrace 比 strace / perf 通常开销小 5-10x。但还是有开销:
- tracepoint:几乎零(编译时插入的探测点)
- kprobe / uprobe:每次触发都中断到 BPF 解释器,有一点开销
- 高频事件(每秒百万级)+ map 写:可能加 5-15% CPU
生产环境 attach 前先估算事件频率,从低开销 tracepoint 开始。
10. CO-RE / libbpf-tools
最新的 BPF 工具用 CO-RE(Compile Once, Run Everywhere):
sudo apt install -y libbpf-tools
sudo execsnoop-bpfcc # bcc 版(需要 kernel-devel)
sudo execsnoop # libbpf-tools 版(任意内核 5.4+)
CO-RE 工具不需要内核头文件,便携性最好。生产首选 libbpf-tools。
踩过的坑
- 老内核(< 5.0)功能阉割严重;如果没法升内核,回退到 strace / perf。
- BTF(BPF Type Format)没启用的内核:很多 bpftrace 脚本直接报错。
ls /sys/kernel/btf/vmlinux看是否有,没有就只能用 kprobe 而非 fentry。 - 一个 bpftrace 脚本里写 5+ 个 probe + 大 map → BPF verifier 拒绝
("too many instructions" / "stack overflow")。拆成多个脚本。 - 容器内跑 bpftrace 没权限:需要
--privileged+--cap-add SYS_ADMIN,
或者直接在 host 上跑。
登录后参与评论。