bpftrace 工具手册速览
一、工具基础介绍
1.1 核心功能定位
bpftrace 是基于 eBPF(Extended Berkeley Packet Filter)技术的下一代跟踪工具,提供以下核心能力:
- 动态追踪:无需重启即可附加探针到内核/用户态函数
- 低开销监控:利用 eBPF 验证器确保安全执行
- 高级语言支持:采用类C语法简化探针开发
- 多数据源融合:同时捕获内核事件、性能计数器、网络数据
- 实时分析:支持直方图、热力图等可视化输出
1.2 架构演进
二、安装与配置
2.1 基础安装
Linux发行版:
# Ubuntu/Debian
sudo apt-get install bpftrace
# CentOS/RHEL
sudo yum install bpftrace
# Fedora
sudo dnf install bpftrace
macOS:
brew install bpftrace
2.2 权限配置
# 临时提权
sudo bpftrace <script.bt>
# 持久化配置(Linux)
echo 'kernel.unprivileged_bpf_disabled=0' | sudo tee /etc/sysctl.d/bpftrace.conf
sudo sysctl -p /etc/sysctl.d/bpftrace.conf
2.3 内核要求
- 最低版本:Linux 4.1+(推荐5.8+)
- 必要配置:
CONFIG_DEBUG_INFO_BTF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_EVENTS=y
三、基础语法详解
3.1 探针类型
类型 | 描述 | 示例 |
---|---|---|
kprobe | 内核函数入口/出口 | kprobe:tcp_v4_connect |
uprobe | 用户态函数入口 | uprobe:/usr/bin/curl:main |
tracepoint | 静态跟踪点 | tracepoint:syscalls:sys_enter_openat |
profile | 周期性采样 | profile:hz:99 每秒99次采样 |
interval | 时间间隔触发 | interval:s:1 每秒触发 |
software | 软件事件 | software:page-faults |
3.2 内置变量
变量 | 类型 | 描述 |
---|---|---|
pid | uint64 | 进程ID |
tid | uint64 | 线程ID |
uid | uint64 | 用户ID |
comm | string | 进程名 |
args | 结构体 | 函数参数(kprobe专用) |
retval | uint64 | 函数返回值(kretprobe专用) |
cpu | int | CPU编号 |
curtask | task_struct* | 当前任务结构体指针 |
3.3 映射表操作
哈希映射:
BEGIN
{
@count = 0; // 初始化计数器
}
kprobe:tcp_sendmsg
{
@count = count + 1;
}
END
{
print(@count);
}
直方图:
kprobe:do_sys_open
{
@latency = hist(args->dfd); // 按文件描述符统计
}
热力图:
profile:hz:99
{
@stacks = lhist(args->stack_id, 0, 1000000, 10000);
}
3.4 控制流语句
条件判断:
kprobe:tcp_v4_connect
{
if (args->ip->daddr == 0x7F000001) {
printf("Localhost connection\n");
}
}
循环结构:
BEGIN
{
@arr = lhist();
}
tracepoint:syscalls:sys_enter_read
{
for (i = 0; i < 10; i++) {
@arr[i] = count();
}
}
四、实战案例分析
4.1 网络分析
TCP重传检测:
kprobe:tcp_retransmit_skb
{
printf("Retransmit detected: PID=%d, SEQ=%llu\n", pid, args->seq);
}
连接跟踪:
kprobe:tcp_v4_connect
{
printf("New connection: %s:%d -> %s:%d\n",
comm,
args->us->sport,
str(args->ip->daddr),
args->us->dport);
}
4.2 性能调优
系统调用延迟分析:
tracepoint:syscalls:sys_enter_openat
{
@start[tid] = nsecs;
}
tracepoint:syscalls:sys_exit_openat
{
@latency = hist(nsecs - @start[tid]);
delete(@start[tid]);
}
CPU火焰图生成:
bpftrace -e 'profile:hz:99 {@[stack] = count();}' -o flame.stacks
./FlameGraph/stackcollapse-bpftrace.pl flame.stacks | ./FlameGraph/flamegraph.pl > flame.svg
4.3 安全审计
隐蔽通道检测:
kprobe:security_socket_sendmsg
{
if (args->msg->msg_flags & MSG_MORE) {
printf("Potential covert channel: PID=%d, LEN=%d\n", pid, args->msg->msg_iter->count);
}
}
异常进程监控:
kprobe:execve
{
printf("New process: %s(%d) launched by %s(%d)\n",
str(args->filename),
pid,
str(comm),
tid);
}
五、高级功能集成
5.1 BCC工具协同
混合编程示例:
from bcc import BPF
bpf_text = """
kprobe:tcp_sendmsg
{
@packets = count();
}
"""
b = BPF(text=bpf_text)
b.attach_kprobe(event="tcp_sendmsg", fn_name="kprobe__tcp_sendmsg")
b["@packets"].print_log2_hist("Packets per second")
5.2 持久化存储
环形缓冲区配置:
BEGIN
{
@ring = ringbuf(1024); // 1MB环形缓冲区
}
kprobe:do_nanosleep
{
@ring.push(args->requested_time);
}
5.3 共享映射表
进程间通信:
// 写入端
kprobe:do_fork
{
@shared[pid] = comm;
}
// 读取端
kprobe:do_exit
{
if (@shared[pid]) {
printf("Process %s exited\n", @shared[pid]);
delete(@shared[pid]);
}
}
六、调试与优化
6.1 验证器日志
启用详细验证:
bpftrace -d 'kprobe:tcp_sendmsg { @cnt = count(); }' 2> verifier.log
日志分析:
; int __attribute__((always_inline)) count(void) {
; @cnt += 1;
; }
0: (bf) r6 = r1
1: (61) r1 = *(u32 *)(r6 + 12)
2: (61) r2 = *(u32 *)(r6 + 16)
3: (b7) r3 = 1
4: (71) r2 = *(u8 *)(r1 + r2)
5: (55) if r2 != 0x40 goto pc+13
R1=map_value(id=0,off=0,ks=4,vs=8,imm=0) R2=inv(id=0) R3=inv1 R6=ctx R10=fp0
; ... 省略后续指令 ...
6.2 性能优化技巧
- 避免内核态拷贝:使用
str()
代替user_string()
- 减少映射操作:批量更新代替单条记录
- 利用BTF信息:自动解析结构体成员
- 限制采样频率:通过
interval
探针控制负载
七、生态工具链
7.1 可视化套件
工具名称 | 功能描述 | 示例命令 |
---|---|---|
FlameGraph | 火焰图生成 | ./flamegraph.pl perf.fold > perf.svg |
ebpf-exporter | Prometheus指标导出 | ebpf_exporter --config.yaml |
Grafana | 仪表盘展示 | 配置bpftrace数据源 |
7.2 扩展库
库名称 | 功能描述 | 典型用例 |
---|---|---|
libbpf | eBPF底层API | 开发自定义探针 |
BCC | Python绑定库 | 构建复杂监控系统 |
Aya | Rust eBPF框架 | 开发安全关键应用 |
八、最佳实践指南
8.1 脚本开发规范
- 使用
#pragma bpftrace option
控制行为:#pragma bpftrace option interval=1000 // 1秒刷新周期 #pragma bpftrace option max_active_probes=1024
- 添加
BEGIN
/END
块进行初始化/清理 - 使用
@
前缀声明映射表变量 - 避免在探针处理函数中执行阻塞操作
8.2 生产环境部署
- 资源限制:
bpftrace -B 1024 --max-probes 4096 <script.bt>
- 日志轮转:
BEGIN { $log_file = "trace.log"; } kprobe:do_sys_open { @fp = fopen($log_file, "a"); fprintf(@fp, "Open event: %s\n", str(args->filename)); fclose(@fp); }
8.3 故障排查手册
-
现象:
Resource temporarily unavailable
原因:达到最大映射表数量
解决方案:增加/proc/sys/kernel/bpf_map_max_entries
-
现象:
Invalid probe type
原因:探针类型与事件不匹配
解决方案:使用trace --list
验证事件存在性 -
现象:
Permission denied
原因:未启用非特权eBPF
解决方案:设置kernel.unprivileged_bpf_disabled=0