https://cloud.tencent.com/developer/article/2031857?areaSource=103001.19&traceId=rX8kmZPurwFtXqEtY-bY-
作为一个程序员,在日常工作中,我们往往对于程序的运行情况十分关注,而随着计算机系统变得越来越复杂,人们想要详细地了解软件和系统内核的行为也变得越来越困难,这导致在计算机系统中,“黑天鹅”事件越来越多,甚至很多“黑天鹅”事件其实是长期没有被发现的“灰犀牛”事件。因此,从系统中收集和分析数据显得至关重要。此时,一个能够监控、嗅探内核运行状态的工具包就显得十分重要了,BPF 就是这样一个工具包。
linux 内核提供了 CPU 调度器、网络调度器、文件调度器等重要功能,我们经常会去使用它们提供的系统调用来与操作系统内核进行交互,但我们如何观测它们的运行状态呢?BPF 就提供了这样的观测手段。
BPF 是 Berkeley Packet Filter 的缩写,它诞生于 1992 年,用来提升网络包过滤工具的性能,直到 2014 年,被正式并入 Linux 内核主线,由此,BPF 成为了一个更通用的执行引擎,可以完成多种任务,尤其是可以创建先进的性能分析工具。
实际上,网络抓包工具 tcpdump 就是通过调用内核的 BPF 工具来实现的,起初 BPF 就是为了 tcpdump 这样想要观测网络事件的工具而服务的,但可想而知,既然网络包可以作为观测的事件源,那么,CPU 采样计数器、内核系统调用、用户态函数调用等等都可以作为事件源,于是扩展 BPF 支持这些事件的观测就显得顺理成章了。
经过扩展后的 BPF 缩写为 eBPF,但也经常仍被称为 BPF,实际上,现在 linux 内核中只有一个 BPF 执行隐层,它同时支持 eBPF 与经典的 BPF 程序,因此,在实际使用中无需区分。
下图展示了 linux 内核中一个通用的系统软件栈,以及 BPF 性能工具可以进行观测的观测点:
尽管有了 BPF 指令,我们就可以对内核进行跟踪、嗅探、采样等操作获取内核中的运行数据来进行分析,但直接使用 BPF 指令过于繁琐复杂,所以我们希望能够有封装好的工具直接方便快捷地使用,甚至使用高级语言进行编程,于是,BCC、bpftrace 两大工具集就诞生了。
BCC 是最早用于开发 BPF 跟踪程序的高级语言框架,它提供了一个编写内核 BPF 程序的 C 语言环境,同时提供了供其他高级语言,诸如 C++、Python、Java 调用的用户端接口。BCC 的成功,产生了 libbcc 和 libbpf 两个函数库,他们提供了使用 BPF 程序对事件进行观测的库函数。
通常,我们直接使用 BCC 提供的工具就可以实现我们需要的功能,但如果我们希望开发一个常态化监控的后台进程,或者是开发复杂的脚本,甚至希望能够调用其他语言的库来实现更为复杂的功能,此时 BCC 就是一个非常强大的工具。
bpftrace 是新近出现的专门用于创建 BPF 工具的高级语言支持框架,使用 bpftrace 编写跟踪程序非常方便、快捷,你也可以阅读 bpftrace 工具的源码,非常简洁易懂。和 BCC 一样,bpftrace 也是基于 libbcc 和 libbpf 构建的。
依赖于 bpftrace 强大的语法,针对于单行程序、短小的脚本来说,bpftrace 可以快速实现其功能。
IO Visor 是一个 Linux 基金会项目,BCC 和 bpftrace 都不在内核代码中维护,而是由 IO Visor 在 Github 中维护的:
https://github.com/iovisor/bcc https://github.com/iovisor/bpftrace
参考 github 仓库中的 readme,我们可以快速安装 BCC 和 bpftrace 仓库。
它们都需要使用 Linux4.9 版本以上内核。
如果你使用的是 ubuntu 系统,你需要执行:
sudo apt install bpfcc-tools linux-headers-$(uname -r)
或者:
sudo snap install bcc
如果你是用的是 RedHat,你需要执行:
sudo yum install bcc-tools
不过最方便的是直接使用官方封装好的 docker 镜像来启动:
sudo docker run -it -v /usr/src:/usr/src:ro -v /lib/modules/:/lib/modules:ro -v /sys/kernel/debug/:/sys/kernel/debug:rw --net=host --pid=host --privileged quay.io/iovisor/bcc:latest bash
安装完成后,BCC 工具通常会被默认放置在 /sbin 目录下,并且以 -bpfcc 为后缀,或者在 /usr/share/bcc/tools 目录下。
ubuntu 下你需要执行:
sudo apt install bpftrace
fedora 下你需要执行:
sudo dnf install -y bpftrace
同样,你也可以使用 docker 镜像来启动:
sudo docker run -it -v /usr/src:/usr/src:ro -v /lib/modules/:/lib/modules:ro -v /sys/kernel/debug/:/sys/kernel/debug:rw --net=host --pid=host --privileged quay.io/iovisor/bpftrace:latest bash
安装完成后,bpftrace 的二进制文件通常会放到 /usr/local/bin/bpftrace,bpftrace 工具则会被安装到 /usr/local/share/bpftrace/tools 中,或者直接放置到 /usr/local/bin 下。
既然完成了 BCC 的安装,你是不是已经跃跃欲试,想要执行一个命令来实践一下了呢?
那么,我们就来执行一个监控系统中进程创建的工具 -- execsnoop
下图是我开启 execsnoop 工具后,用 C 语言编写一个 hello_world 程序并执行后的信息:
下面的代码以 syscall:sys_enter_openat 作为插桩点,实现了对每个进程执行 open() 系统调用的跟踪: