深入理解eBPF与可观测性
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.1.2 eBPF的发展史

eBPF由BPF(BSD Packet Filter或Berkeley Packet Filter)扩展而来。在1992年的USENIX会议上,Steven McCanne和Van Jacobson发布了论文“The BSD Packet Filter:A New Architecture for User-level Packet Capture”,这篇论文首次详细介绍了BPF(即cBPF)的设计和实现原理,其中主要包括cBPF指令集、cBPF虚拟机和cBPF过滤器的实现。

直到2014年,cBPF有了进一步的发展。Alexei Starovoitov将cBPF扩展为一个通用的虚拟机,即eBPF。相比于cBPF,eBPF重新设计了指令集。新指令集更接近机器指令,以便于后续将该指令集和机器指令进行一对一的JIT编译。而且,eBPF指令集能够让我们编写更复杂、更实用的eBPF程序。此外,eBPF引入了JIT编译器,相比于cBPF的解释器在性能上有了极大提升。此外,eBPF还引入了verifier,在扩大应用范围的同时确保了安全性。

2015年,LLVM(Low Level Virtual Machine)编译器支持将C语言代码编译生成eBPF字节码,告别了采用汇编形式的伪代码编写eBPF程序的时代。

随后,大名鼎鼎的Brendan Gregg利用BCC让eBPF声名大噪。BCC将C语言的eBPF程序和Python编程语言结合起来,给我们编写eBPF程序带来了全新的体验。C语言编写的eBPF程序负责在内核收集统计数据或生成事件,然后对应的用户空间的Python程序会收集这些数据并进行处理,充分利用了Python简单、快捷的特点,降低了eBPF的开发门槛。

2018年,BTF(BPF Type Format,BPF类型格式,参见第3章)被引入内核。BTF是一种类似于DWARF的格式,用于描述程序中的数据类型。在BTF的帮助下,eBPF的verifier能够借助BTF来进行验证,以确保eBPF程序访问内存的安全性。

2019年,bpftrace提供了一种简洁的声明式类C语言的脚本编程语法,使用户能够轻松编写和执行跟踪脚本。

2020年,libbpf基于BTF实现了CO-RE(Compile Once-Run EveryWhere,一次编译,到处运行,参见第3章)功能,使得我们能够将eBPF程序打包成二进制,而不需要在目标机器上部署Clang、LLVM等编译工具,降低了eBPF工具的部署难度,提升了易用性。值得一提的是,大部分生产环境使用的工具都是基于libbpf来进行开发的。此外,libbpf还提供了从DWARF到BTF转换的能力,通过去重算法能将300MB的DWARF信息转换成3MB的BTF文件。