eBPF 与 bpftrace 实战教程:Linux 内核可观测性与动态追踪
eBPF(Extended Berkeley Packet Filter)是现代 Linux 内核中最强大的可观测性技术之一。它允许开发者在内核空间安全地运行沙箱程序,无需修改内核源码或加载内核模块,就能动态追踪系统调用、网络流量、磁盘 I/O 等底层事件。结合 bpftrace 这一高层次追踪语言,运维工程师和性能工程师可以用极少的代码实现过去只有内核开发者才能完成的诊断工作。
bpftrace 是基于 eBPF 构建的单行脚本语言,语法类似 awk 和 DTrace,学习曲线平缓。bcc(BPF Compiler Collection)则提供了一套完整的 Python/C 工具集,内置数十个生产可用的诊断工具,覆盖 CPU 调度、文件系统、网络协议栈等各个层面。两者配合使用,可以在不停机、不重启的情况下对线上系统进行深度剖析。
本教程将带你从零开始安装配置 bpftrace 和 bcc tools,掌握常用的单行脚本编写技巧,深入追踪系统调用、网络连接和磁盘 I/O,并通过真实案例展示如何快速定位生产问题。
服务器配置
运行 eBPF 程序需要 Linux 内核版本 4.9 以上(推荐 5.4+),且需要 root 权限。对于学习和实验场景,一台普通的 VPS 即可满足需求。
推荐使用雨云服务器 rainyun-com,注册填优惠码2026off领 5 折优惠券。选择2 核 4GB 机型,搭配 Ubuntu 22.04 LTS 或 Debian 12,内核版本 5.15 以上,完全满足 bpftrace 和 bcc 的运行要求。该配置在运行内核追踪时不会有明显性能损耗,适合长期学习和轻量级生产监控。
安装准备工作
确认内核版本
uname-r# 输出示例:5.15.0-107-generic内核需大于等于 4.9,推荐 5.4+。对于完整的 BTF(BPF Type Format)支持,推荐 5.8+。
安装 bpftrace
Ubuntu 22.04 / Debian 12:
sudoaptupdatesudoaptinstall-ybpftrace从源码编译最新版(可选):
sudoaptinstall-ycmake libelf-dev zlib1g-dev libfl-dev clang llvmgitclone https://github.com/bpftrace/bpftracecdbpftracemkdirbuild&&cdbuild cmake..-DCMAKE_BUILD_TYPE=Releasemake-j$(nproc)sudomakeinstall安装 bcc tools
sudoaptinstall-ybpfcc-tools linux-headers-$(uname-r)# bcc 工具通常以 -bpfcc 后缀安装,如 execsnoop-bpfcc验证安装:
sudobpftrace--version# bpftrace v0.21.xsudoopensnoop-bpfcc# 测试 bcc 工具详细配置
bpftrace 基本语法
bpftrace 程序由探针(probe)和动作(action)组成:
probe [, probe] /filter/ { action }常用探针类型:
| 探针类型 | 说明 | 示例 |
|---|---|---|
tracepoint | 内核静态追踪点 | tracepoint:syscalls:sys_enter_read |
kprobe | 内核函数入口 | kprobe:vfs_read |
kretprobe | 内核函数返回 | kretprobe:vfs_read |
uprobe | 用户态函数入口 | uprobe:/bin/bash:readline |
software | 软件事件 | software:cpu-clock:1ms |
interval | 定时器 | interval:s:1 |
追踪系统调用
追踪所有 open/openat 系统调用:
sudobpftrace-e' tracepoint:syscalls:sys_enter_openat { printf("%-6d %-16s %s\n", pid, comm, str(args->filename)); }'统计各进程 read 系统调用次数(每秒输出):
sudobpftrace-e' tracepoint:syscalls:sys_enter_read { @[comm] = count(); } interval:s:1 { print(@); clear(@); }'追踪系统调用延迟(直方图):
sudobpftrace-e' tracepoint:syscalls:sys_enter_read { @start[tid] = nsecs; } tracepoint:syscalls:sys_exit_read /@start[tid]/ { @latency_us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'追踪网络 I/O
追踪 TCP 连接建立:
sudobpftrace-e' tracepoint:sock:inet_sock_set_state /args->newstate == 1/ { printf("%-6d %-16s %s -> %s\n", pid, comm, ntop(args->saddr), ntop(args->daddr)); }'统计进程网络发送字节数:
sudobpftrace-e' kprobe:tcp_sendmsg { @bytes[comm] = sum(arg2); } interval:s:5 { print(@bytes); clear(@bytes); }'追踪磁盘 I/O
追踪块设备 I/O 延迟:
sudobpftrace-e' tracepoint:block:block_rq_issue { @start[args->dev, args->sector] = nsecs; } tracepoint:block:block_rq_complete /@start[args->dev, args->sector]/ { @io_ms = hist((nsecs - @start[args->dev, args->sector]) / 1000000); delete(@start[args->dev, args->sector]); }'进阶用法
使用 bcc tools 内置工具集
bcc 提供了大量开箱即用的工具,以下是最常用的几个:
execsnoop— 追踪所有新进程创建:
sudoexecsnoop-bpfcc# PCOMM PID PPID RET ARGS# bash 12345 12344 0 /bin/bashbiolatency— 块 I/O 延迟直方图:
sudobiolatency-bpfcc-D101tcpconnect— 追踪主动 TCP 连接:
sudotcpconnect-bpfcc-t# TIME(s) PID COMM IP SADDR DADDR DPORTrunqlat— CPU 调度延迟分析:
sudorunqlat-bpfcc51profile— CPU 火焰图采样:
sudoprofile-bpfcc-F9930>/tmp/out.stacks# 配合 flamegraph.pl 生成火焰图gitclone https://github.com/brendangregg/FlameGraph ./FlameGraph/stackcollapse.pl /tmp/out.stacks|./FlameGraph/flamegraph.pl>cpu_flame.svg追踪用户态函数
追踪 Python 应用的函数调用:
sudobpftrace-e' uprobe:/usr/bin/python3:PyObject_Call { printf("Python call: pid=%d\n", pid); }'追踪 Nginx 处理请求延迟:
sudobpftrace-e' uprobe:/usr/sbin/nginx:ngx_http_process_request { @start[tid] = nsecs; } uretprobe:/usr/sbin/nginx:ngx_http_process_request /@start[tid]/ { @ms = hist((nsecs - @start[tid]) / 1000000); delete(@start[tid]); }'内核函数追踪与参数读取
使用kprobe追踪 VFS 层读取操作:
sudobpftrace-e' kprobe:vfs_read { @[comm] = sum(arg2); // arg2 是 count 参数 } END { print(@); }'列出可用的追踪点:
sudobpftrace-l'tracepoint:syscalls:*'|head-20sudobpftrace-l'kprobe:tcp_*'|head-20实战示例
案例一:定位高 I/O 等待进程
生产环境 I/O wait 飙高,用以下脚本快速定位:
sudobpftrace-e' tracepoint:block:block_rq_issue { @[comm, pid] = count(); } interval:s:3 { print(@); clear(@); printf("---\n"); }'输出示例:
@[mysqld, 1234]: 842 @[rsync, 5678]: 223 @[jbd2/sda1-8, 89]: 45案例二:追踪慢查询 SQL 连接
# 追踪 MySQL 建立的所有 TCP 连接sudotcplife-bpfcc-p$(pgrep mysqld|head-1)案例三:分析文件系统热点
sudobpftrace-e' tracepoint:syscalls:sys_enter_openat { @files[str(args->filename)] = count(); } END { print(@files, 20); // 打印 top 20 }'常见问题
Q:运行 bpftrace 报 “ERROR: failed to attach kprobe”
A:检查内核是否启用了CONFIG_BPF_KPROBE_OVERRIDE,或尝试使用tracepoint替代kprobe。部分云服务器内核可能限制了 kprobe,可改用 tracepoint 探针。
Q:提示 “BTF not found”
A:安装 BTF 支持:
sudoaptinstall-ylinux-image-$(uname-r)-dbg# 或确认 /sys/kernel/btf/vmlinux 文件存在ls/sys/kernel/btf/vmlinuxQ:bpftrace 脚本执行后输出为空
A:检查探针名称是否正确,使用bpftrace -l列出可用探针。注意不同内核版本的追踪点名称可能有差异。
Q:如何减少 bpftrace 对系统性能的影响
A:使用采样机制(/pid % 10 == 0/)降低采样频率,避免在高频探针中执行复杂操作,优先使用聚合操作(@map)代替printf。
Q:bcc 工具报 “Unable to find kernel headers”
A:
sudoaptinstall-ylinux-headers-$(uname-r)eBPF 和 bpftrace 是现代 Linux 可观测性工具链的核心,掌握它们能让你在不影响生产系统稳定性的前提下实现深度性能剖析。要充分发挥 eBPF 的能力,一台内核版本较新、资源充足的 Linux 服务器必不可少。推荐选用雨云服务器 rainyun-com的2 核 4GB 机型,注册时填入优惠码2026off可领取 5 折优惠券,以极低的成本搭建专属的内核追踪实验环境,加速你的 eBPF 学习之旅。