直接编写bpftrace脚本并不复杂,但若不了解探针类型与变量作用域,脚本很可能无法运行或输出空白结果,导致问题难以排查。 执行命令无响应的原因 例如,执行命令 bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("hit\n"); }'
Linux内核监控:BPFTrace动态追踪实战指南
作者:技术拾光
时间:2026-05-08
浏览:104
文章目录
直接编写bpftrace脚本并不复杂,但若不了解探针类型与变量作用域,脚本很可能无法运行或输出空白结果,导致问题难以排查。

执行命令无响应的原因
例如,执行命令 bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("hit\n"); }' 后终端无输出,这通常不是脚本错误,而是环境配置问题。
主要原因通常是权限不足或内核未启用对应追踪点。并非所有系统调用的tracepoint都默认可用,尤其是在较旧或特定配置的内核中。
- 确认追踪点存在:执行
ls /sys/kernel/debug/tracing/events/syscalls/sys_enter_open/。若目录不存在,通常表明内核编译时未包含此点。 - 使用root权限:bpftrace需要访问内核追踪接口,务必使用
sudo。 - 检查debugfs挂载:部分发行版(如RHEL/CentOS 8+)默认不挂载debugfs,需手动执行:
sudo mount -t debugfs none /sys/kernel/debug。 - 添加过滤条件:若仅需观察特定进程(例如
curl),添加过滤条件更可靠:/comm == "curl"/ { printf("open by %s\n", comm); }。
kprobe与tracepoint的选择
监控读操作时,kprobe:vfs_read 与 tracepoint:syscalls:sys_enter_read 看似相似,实际存在显著差异。前者为动态插桩,后者是内核预置的静态点,观测行为不同:
- 覆盖范围:
kprobe:vfs_read可捕获内核态所有read路径(包括文件、管道、套接字),但可能被内联优化绕过;tracepoint:syscalls:sys_enter_read仅捕获用户态发起的read()系统调用入口,覆盖范围较窄但更稳定。 - 参数访问方式:
kprobe使用arg0–argN访问寄存器参数;tracepoint需通过结构体字段访问,如args->fd、args->count。 - 性能开销:通常
tracepoint开销更低。kprobe若挂载在高频函数上(如schedule),易触发内核采样限流机制(受perf_event_max_sample_rate控制)。
安全测量函数耗时的方法
测量系统调用耗时常通过map记录开始时间,但需注意避免因线程复用或异常退出导致map键堆积或时间戳覆盖。
- 防止时间戳覆盖:记录开始时间前,需检查键是否已存在:
kprobe:sys_write /!@start[tid]/ { @start[tid] = nsecs; },否则同一线程的连续调用会覆盖前次时间戳。 - 防止内存泄漏:在返回探针中,需先进行非空判断再清理:
kretprobe:sys_write /@start[tid]/ { @dur = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }。 - 键值选择:避免使用
pid作为key。多线程进程中,不同线程的tid不同但共享同一pid,使用pid会导致统计失真。 - 超时处理:添加
interval:s:10 { exit(); }是良好实践,可防止脚本意外卡死。
内存分配监控输出为零的排查
使用 kprobe:__kmalloc 监控内存分配大小时,若输出 arg0 全为零,通常与内核版本差异有关。
__kmalloc 函数的参数顺序可能随内核版本变化。在5.10+内核中,arg0 可能对应分配大小,而在4.19内核中,arg0 可能对应 gfp_flags。硬编码参数位置极易失效。
- 优先使用tracepoint:若内核支持,优先选用
tracepoint:kmalloc:kmalloc,它提供标准化字段,如args->bytes_alloc。 - 验证符号信息:若必须使用kprobe,务必验证当前内核的符号定义:
sudo cat /proc/kallsyms | grep __kmalloc,并结合objdump -t /lib/modules/$(uname -r)/build/vmlinux | grep __kmalloc确认参数布局。 - 注意覆盖完整性:部分内存分配路径(如SLAB分配器内部)不经过
__kmalloc,可能需要配合tracepoint:kmalloc:kmalloc_node等点进行完整观测。
综上所述,bpftrace的核心难点不在于脚本编写,而在于理解每个 arg0、args->xxx、@map 在当前运行内核版本中对应的内存布局与生命周期。动手前若不查阅 /sys/kernel/debug/tracing/events/ 与 /proc/kallsyms,无异于盲目调试。
实用工具推荐
电子包浆
使用 ›绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
图片压缩
使用 ›选择画质和输出格式,预览压缩前后的大小。
相关文章