BPF之前端工具BCC与bpftrace
BPF(伯克利包过滤器)作为内核中的执行引擎,为系统观测和性能分析提供了强大的工具。在这之中,BCC和bpftrace作为前端工具,各有特色。BCC(BPF Compiler Collection)更像是一个多用途的工具箱,适合开发复杂的监控和分析工具,而bpftrace则以简洁的语法和强大的脚本能力著称,适合快速编写观测程序。两者都依赖于底层的BPF机制,但使用场景和编程方式有所不同。
当你需要一个灵活且功能丰富的方式来探查系统行为时,可以考虑使用bpftrace。它允许你通过简单的脚本快速获取性能数据,比如追踪文件操作、监控网络连接,或者分析CPU使用情况。而对于需要更复杂逻辑和长期运行的守护进程,选择BCC会更合适,它提供了更多的API和工具支持,适合深入系统内核的分析和优化。
选择合适的工具取决于你的具体需求:如果是快速原型或临时脚本,bpftrace是你的好帮手;如果你需要构建一个功能全面的系统监控工具,BCC则是更好的选择。两种工具都能让你深入了解系统底层,帮助你发现性能瓶颈,优化应用程序,堪称系统工程师的利器。现在你知道该怎么选择了,是不是迫不及待要试试它们了呢?
BPF前端工具BCC与bpftrace
一、概述
BCC和bpftrace到底是什么,与BPF是什么关系呢?
经过上一篇的介绍,BPF是内核中的执行引擎,BCC和bpftrace则是两个前端工具,比如用户可以直接使用的命令行工具。
BCC与bpftrace又有何区别?
bpftrace是基于BPF和BCC开发出来的,bpftrace适合临时创造单行程序和短小脚本进行观测,而BCC更适合编写复杂的工具和守护进程。BCC提供的API分为内核态和用户态的,而bpftrace只有一种API即bpftrace编程语言。
BCC与bpftrace都是基于libbcc和libbpf库进行构建的。
二、BCC
BCC全称是BPF Compiler Collection,BPF编译器集合,简称BCC,它包含了构建BPF软件的编译器框架和库,是BPF的主要前端项目。
组件
BCC组件可以用Brendan Gregg的一张图来表示:
安装
BPF组件是在内核4.1至4.9之间开发,最好选择内核4.9及以上的系统。
内核配置需要开启(一般默认开启了):
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_EVENTS=y
CONFIG_BPF_JIT=y
CONFIG_HAVE_EBPF_JIT=y
Ubuntu
ubuntu上安装一般可能出现的问题较少,包名字叫bpfcc-tools。
sudo apt install bpfcc-tools linux-headers-$(uname -r)
# 或者
sudo snap install gcc
RHEL
Centos7我试了很久,安装问题总是不断,不推荐。
sudo yum install bcc-tools
# 问题可能出在:
# 1.内核版本过低; 2. 缺少对应的kernel-devel(yum install kernel-devel-$(unamr -r); 3. 缺少kernel-headers)
工具
BCC工具有很多,单一用途或多用途工具都有,可以主要按以下分类:
功能点 | 工具 |
---|---|
调试手段 | trace、argdist、funccount、stackcount、opensnoop |
CPU相关 | execsnoop、runqlat、runqlen、cpudist、profile、offcputime、syscount、softirq、hardirq |
内存相关 | menleak |
文件系统 | opensnoop、filelife、vfsstat、fileslower、cachestat、writeback、dcstat、xfsslower、xfsdist、ext4dist |
磁盘I/O | biolatency、biosnoop、biotop、bitesize |
网络相关 | tcpconnect、tcpaccept、tcplife、tcpretrans |
安全相关 | capable |
三、bpftrace
组件
所有的bpftrace工具都是以.bt作为文件后缀名。前端使用lex和yacc来对bpftrace语言进行词法和语法分析,使用Clang来解析结构体。后端则将bpftrace程序编译成LLVM中间表示形式,再通过LLVM库将其编译为BPF代码。
安装
Ubuntu
sudo apt update
sudo apt install bpftrace
工具
主要分类:
功能点 | 工具 |
---|---|
调试手段 | execsnoop.bt、threadsnoop.bt、opensnoop.bt、killsnoop.bt、signals.bt |
CPU相关 | execsnoop.bt、runqlat.bt、runqlen.bt、cpuwalk.bt、offcputime.bt |
内存相关 | oomkill.bt、failts.bt、vmscan.bt、swapin.bt |
文件系统 | vfsstat.bt、filelife.bt、xfsdist.bt |
存储I/O | biosnoop.bt、biolatency.bt、bitesize.bt、biostacks.bt、scsilatency.bt、nvmelatency.bt |
网络相关 | tcpaccept.bt、tcpconnect.bt、tcpdrop.bt、tcpretrans.bt、gethostlatency.bt |
安全相关 | ttysnoop.bt、elfsnoop.bt、setuids.bt |
编程相关 | jnistacks.bt、javacalls.bt |
应用相关 | threadsnoop.bt、pmheld.bt、naptime.bt、mysqld_qslower.bt |
内核相关 | mlock.bt、mheld.bt、kmem.bt、kpages.bt、workq.bt |
容器相关 | pidnss.bt、blkthrot.bt |
虚拟机 | xenhyper.bt、cpustolen.bt、kvmexits.bt |
bpftrace编程
基础语法
1. 程序结构
bpftrace程序结构是一系列探针加对应的动作
probes { actions }
probes { actions }
...
探针被激活时,相应动作会被执行。也可以在探针前设置一个可选的过滤表达式
probes /filter/ { actions }
/pattern/ { actions }
2. 注释
单行代码使用"//"来注释
// this is a comment
多行代码注释和C语言一样
/ this is * a muti-line* comment*/
3. 探针格式
探针(probe)以类型名开始,然后是一系列冒号分隔的标识符
type:identifier1[:identifier2[...]]
标识符的组织形式由探针类型决定,比如
kprobe:vfs_read
uprobe:/bin/bash:readline
- kprobe探针类型,内核态函数插桩,只需要一个标识符:内核函数名
- uprobe探针类型,用户态函数插桩,需要两个标识符:二进制文件路径和函数名
可以使用逗号将多个探针并列,指向同一个执行动作,如
probe1,probe2,... { actions }
有两个特殊的探针类型不需要标识符:BEGIN和END,它们会在bpftrace程序启动和结束时触发(类似awk命令)
4. 探针通配符
有些探针接受通配符,比如下面这个,会对有的以"vfs_"开头的内核函数进行插桩
kprobe:vfs_*
但如果同时开启很多的函数插桩,对性能有影响。环境变量"BPFTRACE_MAX_PROBES"可以设置探针数量上限。
也可以插桩之前使用"bpftrace -l"命令进行统计有多少个探针数量比配,做个评估
bpftrace -l "kprobe:vfs_*" | wc -l
5. 过滤器
过滤器是一个布尔表达式,决定一个动作是否被执行
//过滤进程pid为123
/pid == 123///筛选pid为非零
/pid///过滤器也可使布尔运算组合
/pid > 100 && pid < 1000/
6. 执行动作
一个动作既可以是单条语句