BPF-eBPF 学习总览:从概念、机制到工具链选择
世界上只有一种真正的英雄主义,就是在认清生活的真相后依然热爱生活。——罗曼·罗兰
写在前面
- 这篇文章的目标不是只解释
BPF/eBPF的定义,而是给出一条由浅及深、能真正走通的学习路线 - 内容会从
概念认知、运行机制、学习顺序、工具链选择一直讲到BCC、libbpf和ebpf-go的入门方式 - 如果你是第一次接触 eBPF,建议先把
为什么它重要和它是怎么运行起来的搞明白,再开始写程序 - 理解不足小伙伴帮忙指正 :)
世界上只有一种真正的英雄主义,就是在认清生活的真相后依然热爱生活。——罗曼·罗兰
持续分享技术干货,感兴趣小伙伴可以关注下 ^_^
系列导航
这一组文章统一放在 source/_posts/rhca/RH442_BPF/BPF/eBPF学习路线/ 目录下,阅读顺序建议如下:
BPF-eBPF 学习总览:从概念、机制到工具链选择BPF-eBPF 实战入门:环境准备、最小实验与排错思路BPF-eBPF 开发路线一:BCC 入门、工具使用与自定义脚本BPF-eBPF 开发路线二:libbpf、CO-RE 与 libbpf-bootstrap 实战BPF-eBPF 开发路线三:ebpf-go、bpf2go 与 Go 工程集成
这一篇侧重认知框架和学习路线,后面几篇侧重环境、命令、示例和代码组织。
先给结论:BPF 应该怎么学
如果你想少走弯路,我建议按下面这个顺序学习:
- 先理解
BPF/eBPF的核心概念,至少搞懂:hook、program type、map、helper、verifier、JIT - 再理解 eBPF 为什么适合做
networking、observability、security - 然后用现成工具先建立直觉,比如看别人已经写好的
BCC工具在观测什么 - 之后再开始写自己的第一个程序,优先做最小实验:
tracepoint、kprobe、uprobe - 等你能写简单程序了,再去系统掌握
CO-RE、BTF、bpftool、ringbuf/perf buffer、对象生命周期 - 最后根据你的主语言和目标场景,在
BCC、libbpf、ebpf-go之间做取舍
一句话概括:
- 想
快速上手、快速验证想法,先看BCC - 想
贴近内核、做主流生产级开发,重点学libbpf - 想
用户态用 Go 集成、做可分发工具,重点学ebpf-go
什么是 BPF,什么是 eBPF
BPF 最早是 Berkeley Packet Filter,最初和网络包过滤强相关。
后来 Linux 内核把它演进成了一个更通用的执行引擎,也就是今天大家常说的 eBPF。在官方文档和社区里,BPF 与 eBPF 往往会混用;严格说:
cBPF指经典 BPFeBPF指扩展后的 BPF- 现在内核和很多文档里经常直接写
BPF
根据 ebpf.io 的介绍,eBPF 本质上是在 Linux 内核中运行的一套沙箱化程序机制,可以在不修改内核源码、不加载传统内核模块的前提下,安全地扩展内核能力。
它今天最重要的三个应用方向是:
网络可观测性安全
这也是为什么 eBPF 这几年会这么火。它不是单纯的“抓包工具升级版”,而是一种可以把观测逻辑、过滤逻辑、安全策略、数据采样逻辑放进内核关键路径执行的能力。
学 eBPF 之前,先建立一张脑图
很多人学 eBPF 卡住,不是因为语法难,而是因为脑子里没有完整的运行模型。你至少要先建立下面这张“心智模型”。
1. 程序不是主动运行的,而是挂在 hook 上
eBPF 程序是事件驱动的,不是像普通用户态程序那样自己主动跑起来。
它会挂载在某个 hook point 上,等事件发生时再执行,例如:
kprobe/kretprobe:挂在内核函数入口/返回tracepoint:挂在内核预定义跟踪点uprobe/uretprobe:挂在用户态函数入口/返回XDP:挂在网络收包非常早的阶段tc:挂在流量控制路径perf_event:做采样类分析LSM:做安全控制
你可以把 eBPF 理解成:
程序本体挂载位置和用户态交换数据的方式
这三件事缺一不可。
2. eBPF 程序不能乱来,它要过 verifier
eBPF 最核心的安全机制之一就是 verifier。
根据 ebpf.io 的介绍,程序在加载到内核前会经过校验,验证器会确保它:
- 不会非法访问内存
- 不会无限循环不退出
- 不会使用未初始化变量
- 复杂度在内核允许的范围内
所以你学习 eBPF,不能只想着“怎么写代码”,还要学会“怎么写出 verifier 能接受的代码”。
3. eBPF 程序很小,复杂状态通常放在 map 里
eBPF 程序本身执行时间短、约束强,不适合在里面维护复杂业务状态,因此大量状态和数据交换依赖 BPF map。
docs.ebpf.io 将 map 类型分成了很多类,常见的有:
HASHARRAYPERCPU_HASHPERCPU_ARRAYLPM_TRIERINGBUFPERF_EVENT_ARRAYPROG_ARRAY
学 eBPF 时,map 绝对不是附属知识,而是主知识。很多程序难点根本不在 probe,而在:
- 数据怎么聚合
- 如何把内核态数据送到用户态
- 怎么避免竞争
- 怎么控制开销
4. eBPF 不是直接调用任意内核函数,而是通过 helper/kfunc 等受控能力
eBPF 程序不能像内核模块那样随便调用内核内部函数,而是依靠内核暴露的能力接口,例如:
helper functions- 一些场景下的
kfunc
这也是它能兼顾灵活性和安全性的原因之一。
5. 最终是“内核态采集 + 用户态控制/展示”
绝大多数 eBPF 应用都不是纯内核态,也不是纯用户态,而是“两段式结构”:
内核态 eBPF 程序负责挂点、采集、过滤、聚合用户态程序负责加载、附加、读取 map/ringbuf、展示或上报
你后面无论使用 BCC、libbpf 还是 ebpf-go,本质上都在做这件事,只是工程组织方式不同。
初学者到底需要哪些前置知识
如果下面这些你完全陌生,建议先补一下,不然学 eBPF 会非常痛苦:
Linux 基础:进程、线程、文件、权限、系统调用内核基础:用户态/内核态、调度、中断、网络栈、VFS 的基本概念C 语言基础:结构体、指针、内存布局调试与观测:strace、perf、ss、tcpdump、bpftool编译基础:至少知道clang/LLVM在这里扮演什么角色
如果你的目标是用 ebpf-go,那还要有:
Go基础- 对
file descriptor、资源生命周期有基本认知
一条更稳妥的学习路线
下面这条路线适合大多数工程师。
第一阶段:只看概念,不急着写代码
这一阶段只做一件事:先把“eBPF 到底是什么”搞明白。
建议阅读顺序:
ebpf.io/what-is-ebpf/docs.cilium.io里的BPF and XDP Reference Guidedocs.ebpf.io
你在这一阶段至少应该回答这几个问题:
- 为什么 eBPF 可以在内核里运行,但又比传统内核模块更安全
- 什么叫 hook,常见 hook 有哪些
- 什么是 program type
- 什么是 map,为什么 map 很重要
- verifier 在检查什么
- JIT、helper、tail call 分别解决什么问题
如果这些问题答不清楚,不建议直接往“写程序”上冲。
第二阶段:先学会“看”,再学会“写”
不要一上来就手写复杂 eBPF 程序,先学会用别人写好的工具观察系统。
这是因为 eBPF 真正的门槛不只是语法,而是:
- 你想观测什么
- 这个点挂在哪里
- 数据应该如何汇总
- 输出长什么样才有分析价值
所以这一阶段建议你:
- 先跑一些
BCC工具 - 看它们分别在采什么数据
- 观察它们挂了哪些 probe
- 理解为什么有些工具输出直方图,有些输出事件流
比如 bcc 官方仓库里就提供了大量现成工具,覆盖:
tracingmemory and processperformance and timeCPU and schedulernetwork and sockets
这一步非常重要,因为它会帮你建立“eBPF 能解决什么问题”的直觉。
第三阶段:写最小可运行程序
这个阶段不要上来就做复杂项目,而是做最小闭环:
- 写一个最简单的
tracepoint程序 - 把数据打印到
trace_pipe或送到用户态 - 再写一个简单的
kprobe - 再尝试一个
uprobe - 最后尝试一个基于
ringbuf/perf buffer的事件传递
学习顺序建议如下:
tracepoint:最稳,符号稳定,适合入门kprobe:更灵活,但更依赖内核函数细节uprobe:开始接触用户态应用跟踪XDP/tc:进入网络方向LSM:进入安全方向
第四阶段:系统掌握工程化能力
到了这一步,你已经不是“知道 eBPF 是什么”,而是开始“真正做 eBPF 应用”了。
这个阶段要重点掌握:
BTFCO-REbpftoolvmlinux.hpinningring buffer和perf event array- 对象生命周期
- 不同内核版本兼容性
这部分一旦不懂,程序就很容易变成:
- 只能在你自己机器上跑
- 一换内核就挂
- 一上线就因为权限或资源限制失败
三种主流开发方式怎么选
你给出的三种方式,基本就是今天最常见的 eBPF 开发路线。
1. BCC:最适合入门、验证和快速做工具
BCC 是一个 eBPF 工具集和开发框架。根据其官方 README,它提供了大量现成工具,并且支持用 C 编写内核态逻辑,配合 Python/Lua 等前端进行用户态控制。
它的优点:
- 上手快
- 适合教学和原型验证
- 自带很多现成工具,便于学习思路
- 做临时排障、性能分析很高效
它的不足:
- 运行时依赖相对多
- 更依赖目标机环境
- 对生产级可移植性和现代工程化支持,通常不如
libbpf + CO-RE
什么时候学 BCC:
- 你刚开始接触 eBPF
- 你想快速理解各种探针和观测方法
- 你想先写几个实验工具建立信心
一句话评价:BCC 非常适合“学会 eBPF 能干什么”
2. libbpf:最值得深入的主流 C 开发路线
libbpf 是今天 Linux eBPF 生态里非常核心的用户态库。它更贴近内核原生能力,也是很多现代 eBPF 项目的基础设施。
libbpf-bootstrap 官方仓库的定位就很明确:它是一个用于 BPF 应用开发的脚手架,提供了 minimal、bootstrap、kprobe、uprobe、usdt、fentry、xdp、tc 等示例。
尤其是 bootstrap 这个例子,很适合作为真正开始写应用的起点,因为它把很多“必须做但很枯燥”的事先帮你搭好了,例如:
- 加载对象
- 处理命令行参数
- 使用 ring buffer 把数据送到用户态
- 使用
CO-RE和vmlinux.h - 优雅退出
libbpf 的优点:
- 更贴近内核原生生态
CO-RE支持成熟- 更适合做长期维护、生产部署的程序
- 学透之后,对 eBPF 机制理解会更深
它的不足:
- 学习曲线更陡
- 对
ELF section、对象装载、BTF、attach 方式等概念要求更高 - 对 C 语言和内核数据结构理解要求更高
什么时候优先学 libbpf:
- 你想真正掌握 eBPF
- 你要写生产级程序
- 你希望理解内核原生 BPF 应用是怎么组织的
一句话评价:libbpf 非常适合“把 eBPF 学扎实”
3. ebpf-go:适合 Go 工程体系中的 eBPF 集成
ebpf-go 是 Go 生态中非常重要的 eBPF 库。其官方首页明确说明:它是一个用于操作 eBPF 的 Go 库,不依赖 C、libbpf 或其它 Go 库之外的额外运行时依赖,这使它很适合做自包含、可移植的工具。
这条路线很适合:
- 你的用户态控制面本来就是 Go
- 你要把 eBPF 集成到现有 Go 服务或 CLI 中
- 你希望产物分发更方便
ebpf-go 文档里还有两个对初学者很重要的点:
Object Lifecycle:它强调 eBPF 对象本质上围绕文件描述符运作,而 Go 的垃圾回收会影响对象生命周期Portable eBPF:它建议用稳定的 LLVM 工具链生成.o和.go文件,并结合CO-RE/BTF处理跨内核兼容问题
这意味着用 ebpf-go 时,你不仅要会 Go,还要理解:
- 文件描述符何时被关闭
- pinning 何时需要
ProgramArray/tail call 为什么会踩生命周期坑bpf2go生成物是怎么参与构建的
什么时候优先学 ebpf-go:
- 你主力语言是 Go
- 你要开发命令行工具、Agent、Exporter、探针守护进程
- 你不想把用户态控制面写成 C
一句话评价:ebpf-go 非常适合“把 eBPF 融入 Go 工程”
三种方式的选择建议
如果你现在还没有明确方向,可以直接参考这张表:
| 目标 | 更建议的路线 |
|---|---|
| 先建立直觉,快速做实验 | BCC |
| 深入理解 eBPF 核心机制,做主流生产开发 | libbpf |
| 用户态以 Go 为主,想做工程化交付 | ebpf-go |
| 临时排障、性能分析、验证想法 | BCC |
| 做长期维护的底层工具或 Agent | libbpf / ebpf-go |
如果你问我最稳妥的学习顺序,我会建议:
概念 -> BCC 建立直觉 -> libbpf 打基础 -> ebpf-go 做工程集成
一个可执行的 6 周学习计划
如果你希望不是“看完文章很激动”,而是真的开始学,可以按这个节奏走。
第 1 周:概念入门
目标:
- 搞懂 BPF/eBPF 是什么
- 知道常见 hook 和 program type
- 知道 verifier、JIT、map、helper 是什么
产出:
- 能用自己的话解释 eBPF 的运行模型
第 2 周:观察现成工具
目标:
- 跑一些
BCC工具 - 看 CPU、内存、进程、网络四类场景
- 形成“一个问题对应一个挂点和一类数据”的直觉
产出:
- 至少记录 10 个你看过的工具和它们各自解决的问题
第 3 周:第一个最小程序
目标:
- 跑通一个
tracepoint - 跑通一个
kprobe - 理解内核态和用户态怎么通信
产出:
- 你的第一个最小 eBPF Demo
第 4 周:开始 libbpf
目标:
- 看
libbpf-bootstrap - 跑
minimal - 跑
bootstrap - 理解
vmlinux.h、BTF、CO-RE
产出:
- 基于
bootstrap改一个自己的小程序
第 5 周:开始 ebpf-go
目标:
- 跑通
ebpf-go的 getting started - 用
bpf2go生成对象 - 理解 Go 侧如何加载、attach、读取数据
产出:
- 一个 Go 版本的小型观测工具
第 6 周:选一个方向深入
你可以三选一:
可观测性:进程、内存、CPU、IO、网络延迟网络:XDP、tc、socket 相关路径安全:LSM、syscall、进程行为约束
产出:
- 一个可以真正解决问题的小工具,而不是 demo
非常适合新手的练手题
如果你不知道从什么开始写,下面这些题目适合作为练习:
- 统计某个进程的
exec/exit事件 - 跟踪指定进程的文件打开行为
- 统计某个 syscall 的耗时分布
- 观察 TCP 连接建立时延
- 跟踪用户态某个函数的调用次数和耗时
- 用 ring buffer 把事件推给用户态程序
这些练手题的价值在于它们分别覆盖了:
- 事件跟踪
- 数据聚合
- 直方图统计
- 内核态到用户态通信
- probe 选择
- attach 生命周期
学习过程中最容易踩的坑
1. 只记语法,不理解挂点
很多人会背 SEC("kprobe/...")、BPF_HASH 之类写法,但并不知道为什么要挂这个点。这样一旦换问题场景,立刻不会写。
2. 把 eBPF 当成普通 C 去写
eBPF 代码受 verifier 和执行模型强约束,很多普通 C 的写法并不成立。你必须一直带着“这段代码能不能通过 verifier”的意识写。
3. 不理解 map 的角色
很多程序写不出来,本质上不是 probe 不会挂,而是数据结构没设计清楚。
4. 不重视兼容性
如果你以后要把程序部署到不同机器上,就必须理解:
BTFCO-RE- 不同内核版本差异
- 不同发行版内核布局差异
5. 不理解对象生命周期
尤其是 ebpf-go 场景下,文件描述符、GC、pinning、link 生命周期如果没搞清楚,非常容易出现“程序看起来加载成功了,但过一会儿就失效”的问题。
我建议的资料阅读顺序
下面按“从入门到开发”的顺序整理一下你给的参考资料。
第一层:概念入门
https://ebpf.io/what-is-ebpf/https://docs.cilium.io/en/stable/reference-guides/bpf/index.htmlhttps://docs.ebpf.io/
适合解决的问题:
- eBPF 到底是什么
- 运行模型是什么
- 常见 program type、map type、helper 有哪些
- 什么是更系统的技术参考资料
第二层:BCC 入门
https://github.com/iovisor/bcc
建议看法:
- 先不要急着通读源码
- 先看 README 和现成工具清单
- 挑你最关心的方向去读工具实现
适合人群:
- 想快速开始
- 想先建立“观测问题 -> 挂点 -> 数据输出”的直觉
第三层:libbpf 入门与深入
https://github.com/libbpf/libbpf-bootstraphttps://libbpf.readthedocs.io/en/latest/
建议顺序:
- 先从
libbpf-bootstrap的示例开始 - 再去读
libbpf文档 - 最后再结合需要直接看
libbpf源码
适合人群:
- 想系统掌握 eBPF C 开发
- 想进入生产级工具开发
第四层:Go 路线
https://ebpf-go.dev/
建议重点:
Getting StartedPortable eBPFObject Lifecycle
适合人群:
- Go 工程师
- 需要把 eBPF 集成到现有 Go 系统中的同学
一条更现实的工具链建议
很多人纠结“我到底先学 BCC、libbpf 还是 ebpf-go”,其实更现实的答案是:
- 用
BCC学观察问题的方法 - 用
libbpf学 eBPF 的主干知识 - 用
ebpf-go完成工程集成
也就是说,三者不是绝对对立关系,而是很可能在不同阶段各有价值。
如果你是:
运维/性能分析方向:优先BCC -> libbpf底层系统开发方向:优先libbpfGo 平台/Agent/可观测性平台方向:优先libbpf 基础 -> ebpf-go
参考资料与说明
本文整理时主要参考了以下资料:
- What is eBPF?
- BPF and XDP Reference Guide - Cilium
- eBPF Docs
- BCC
- libbpf-bootstrap
- libbpf documentation
- ebpf-go documentation
结合这些资料,可以得到一条比较稳妥的判断:
ebpf.io适合建立整体认知docs.ebpf.io适合作为长期查询手册BCC适合入门和建立问题直觉libbpf是最值得系统深入的主路线ebpf-go非常适合 Go 工程中的实际集成
最后总结
如果你刚开始学 BPF,不要把目标定成“我今天就写出一个很强的 eBPF 工具”,而应该先做到:
- 知道它为什么存在
- 知道它运行在什么位置
- 知道它怎么安全运行
- 知道数据怎么从内核态流到用户态
- 知道三种主流开发方式分别适合什么场景
当这些问题想清楚之后,后面的学习就会顺很多。
真正的学习顺序不是:
背 API -> 抄 demo -> 卡在 verifier
而应该是:
建立模型 -> 学会观察 -> 做最小实验 -> 进入工程化
这样学,eBPF 才会越学越清楚,而不是越学越乱。
博文部分内容参考
© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)
- What is eBPF?
- BPF and XDP Reference Guide - Cilium
- eBPF Docs
- BCC - GitHub
- libbpf-bootstrap - GitHub
- libbpf documentation
- ebpf-go documentation
© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)
BPF-eBPF 学习总览:从概念、机制到工具链选择
https://liruilongs.github.io/2026/04/14/rhca/RH442_BPF/BPF/eBPF学习路线/BPF-eBPF 学习总览:从概念、机制到工具链选择/
1.BPF-eBPF 开发路线三:ebpf-go、bpf2go 与 Go 工程集成
2.BPF-eBPF 开发路线二:libbpf、CO-RE 与 libbpf-bootstrap 实战
3.BPF-eBPF 开发路线一:BCC 入门、工具使用与自定义脚本
4.BPF-eBPF 实战入门:环境准备、最小实验与排错思路
5.Linux性能调优之使用BPF工具观测CPU性能指标
6.认识 Linux 内存构成:Linux 内存调优之内存分配机制和换页行为认知
7.BPF:BCC工具 funccount 统计内核函数调用(内核函数、跟踪点USDT探针)认知
8.BPF:BCC(BPF Compiler Collection)工具集认知

