eBPF(extended Berkeley Packet Filter, 可扩展伯克利包过滤器)
对内核进行动态编程,以实现高效联网、可观察性、可追踪性和安全性
介绍
eBPF
是从 BPF(也称 cBPF:classic Berkeley Packet Filter)
发展而来的,BPF
专门用来过滤网络数据包
eBPF
允许程序在不修改内核源代码,或添加额外的内核模块情况下运行
- 特征
无侵入特性
:观测成本极低,应用无需修改任何代码和重启进程
动态可编程性
:无需重启探针,动态下发 eBPF 脚本即可修改探针侧的逻辑
高性能
:自带 JIT 编译,使探针能够获得内核本地运行的效率
安全
:verifier 机制限制了 eBPF 脚本能够访问的内核函数,保证内核运行的稳定
eBPF 架构
转自
- 用户态
- 用户编写
eBPF
程序,可以使用 eBPF
汇编或者 eBPF
特有的 C 语言来编写
- 使用
LLVM/CLang
编译器,将 eBPF
程序编译成 eBPF
字节码
- 调用
bpf()
系统调用把 eBPF
字节码加载到内核
- 内核态
- 当用户调用
bpf()
系统调用把 eBPF
字节码加载到内核时,内核先会对 eBPF
字节码进行安全验证
- 使用
JIT(Just In Time)
技术将 eBPF
字节编译成本地机器码(Native Code)
- 根据
eBPF
程序的功能,将 eBPF
机器码挂载到内核的不同运行路径上
- 如用于跟踪内核运行状态的
eBPF
程序将会挂载在 kprobes
的运行路径上
- 当内核运行到这些路径时,会触发执行相应路径上的
eBPF
机器码
上图转载自
eBPF 挂载点
bpftrace_probes 参考
相关链接
持续剖析
持续剖析(Continuous Profiling)
是通过动态实时采集应用程序CPU、内存等资源申请的堆栈信息,帮助检测和定位应用程序的性能瓶颈,实现包括
- eBPF
- jstack
火焰图(Flame Graph)
- 分析 CPU 占用、内存分配、内存泄漏、墙中热点、网络 IO、文件 IO、锁竞争、异常
- 实现包括:广义火焰图、冰柱状火焰图
eBPF 使用
BCC 工具
BCC
工具支持使用 Python
和 C
语言组合来编写 eBPF
程序,参考
# ubuntu
sudo apt-get install bcc bpfcc-tools linux-headers-$(uname -r)
$ bcc -v
bcc: version 0.16.17
Usage: bcc [-ansi] [-options] [-o output] file [files].
hello world
C
语言编写 eBPF
内核态
程序:hello.c
int hello_world(void *ctx)
{
bpf_trace_printk("Hello, World!");
return 0;
}
Python
开发 用户态
程序:hello.py
#!/usr/bin/env python3
from bcc import BPF
# 加载 eBPF 内核态程序
b = BPF(src_file="hello.c")
# 将 eBPF 程序挂载到内核探针 kprobe
# do_sys_openat2() 是系统调用 openat() 在内核中的实现
b.attach_kprobe(event="do_sys_openat2", fn_name="hello_world")
# 读取并且打印 eBPF 内核态程序输出的数据
b.trace_print()
$ sudo python3 hello.py
b' <...>-2111 [000] ...21 239.916342: bpf_trace_printk: Hello, World!'
b' irqbalance-962 [001] ...21 242.346380: bpf_trace_printk: Hello, World!'
b' irqbalance-962 [001] ...21 242.346886: bpf_trace_printk: Hello, World!'
...
bpf_trace_printk()
会将信息写入 /sys/kernel/debug/tracing/trace_pipe
中
相关教程