《Linux内核观测技术BPF》
《Linux内核观测技术BPF》
目录
基本介绍
进度记录:20/174 (pdf)
关于书上的代码;https :/loreil.lyllbpf-r叩0
书上的代码 github:https://github.com/bpftools/linux-observability-with-bpf/tree/master
【必看】【必看】【必看】笔记中很多的代码部分我都是直接根据双层pdf的文字层进行复制的,他这个版本的pdf没多余空格这点比较好,但有个非常严重的问题:1l
不分,0o
不分。所以程序仅供参考不能直接用,实在要用需要多注意这两个容易识别错误的地方。不过更建议重打,检查总是会检查漏
书籍目录
- 引言
- PDF的历史
- 架构
- 小结
- 运行第一个BPF程序
- 编写BPF程序
- BPF程序类型
- BPF验证器
- BPF类型格式
- 尾部调用
- 小结
- BPF映射
- 创建BPF映射
- 使用BPF映射
- BPF映射类型
- BPF虚拟文件系统
- 小结
- BPF跟踪
- 探针
- 跟踪数据可视化
- 小结
- BPF工具
- BPFTool
- BPFTrace
- kubectl-trace
- eBPF Exporter
- 小结
- Linux网络和BPF
- BPF和数据包过滤
- 基于BPF的流量控制分类器
- 小结
- XDP
- XDP程序概述
- XPD和BCC
- 测试XDP程序
- XDP用户案例
- 小结
- Linux内核安全、能力和Seccomp
- 能力
- Seccomp
- BPF的LSM钩子
- 小结
- 真实的用户案例
- Sysdig eBPF上帝视角
- Flowmill
引言 - 可观测性
在过去的几十年里,计算机系统变得越来越复杂。人们创建了很多办怯来了解软件的行为,试图解决对复杂系统进行洞察的挑战。
日志
日志是很好的信息来源,常用于获得应用程序可见性。日志为分析应用程序的行为提供了精确数据。
然而,日志分析的方桂受制于应用开发者暴露的日志内容。如果想要收集系统中日志格式以外的信息,则变得和反编译程序来查看执行流一样有挑战。
度量
另外一种流行的方法是使用度量来推断程序的行为。
度量与日志有所不同,日志提供的是显性数据,而度量是通过数据聚合对一个程序在特定时间点的行为进行衡量。
可观测性
- 可观测性是一种新兴的实践,尝试从不同角度来解决问题。可观测性被定义成一种能力,可以对给定系统提出的任意问题,寻求到复杂的答案。
比较
可观测性、日志和度量聚合三者的主要区别是收集的数据内容。
如果可观测性的实践需要随时随地回答任意问题,那么唯一可行的方式就是收集系统中生成的所有数据,在需要回答问题的时候聚合收集到的数据。
Nassim Nicholas Taleb 的畅销书 Antifragile: Things That Gain From Disorder ( Penguin Random Hous巳出版社) ,书中提到的广为人知的"黑天鹅"事件 ( "黑天鹅"事件指产生重大后果的意外事件) ,如果在事件发生前就进行观测,事件是可预料的。
在作者的另一本书 The Black Swan (Penguin Random House 出版社)中,他解释了在一些罕见的事件中,拥有相关数据是如何帮助降低风险的 。
"黑天鹅"事件在软件工程中比我们想象的更常见,而且无战避免。假设我们无法预防这类事件,唯一的选择就是在不影响业务系统的前提下,获得尽可能多的信息来解决问题。
可观测性有助于我们构建健壮的系统,减少"黑天鹅"事件的发生。它的前提条件是我们正在收集的任何数据都能回答未来的任何问题。所以,我们认为对于"黑天鹅"事件的研究和可观测性的实践,核心是从系统中收集到的数据。
历史
1992 年
Steven McCanne 和 Van Jacobson 写了一篇名为 "The BSD Packet Filter: A New Architecture for User-Level Packet Capture" 的论文。在文中,作者描述了他们如何在 Unix 内核实现网络数据包过滤,这种新的技术比当时最先进的数据包过滤技术快 20 倍。
数据包过滤有一个特定的目的 : 可以编写应用程序直接使用内核信息来监控系统网络。有了这些内核信息,应用程序就可以决定如何处理这些数据包。 BPF 在数据包过滤上引入了两大革新:
- 一个新的虚拟机 (VM) 设计 , 可以有效地工作在基于寄存器结构的 CPU 之上。
- 应用程序使用缓存只复制与过滤、数据包相关的数据,不会复制数据包的所有信息。这样可以最大限度地减少 BPF 处理的数据。
由于这些巨大的改进,所有的 Unix 系统都选择采用 BPF 作为网络数据包过滤技术,而放弃了原有消耗大内存和低性能的实现。直到今天,许多 Unix 内核的派生系统中(包括 Linux 内核)仍使用该实现。
2014 年初
Alexei Starovoitov 实现了 eBPF 。新的设计针对现代硬件进行了优化,所以 eBPF 生成的指令集比旧的 BPF 解释器生成的机器码执行得更快。
扩展版本也增加了虚拟机中的寄存器数量,将原有的 2个 32 位寄存器增加到 10 个 64 位寄存器。由于寄存器数量和宽度的增加,开发人员可以使用函数 参数自由交换更多的信息,编写更复杂的程序。总之,这些改进使 eBPF 版本的速度比原来的 BPF 提高了4倍。
eBPF 实现的最初目标是优化处理网络过滤器的内部 BP F 指令集。当时, BPF仍然限于内核空间使用,只有少数用户空间程序可以编写内核处理的 BPF 过滤器,例如 Tcpdump 和 Seccomp ,在后面的章节中我们会讨论这些程序。时至今日,这些程序仍基于旧的 BPF 解释器生成字节码,但内核中会将这些指令转换为高性能的内部表示。
2014 年 6 月
eBPF 1幸 t主 l 扩展到用户空间。这是 B凹的转折点。正如 Alexei 在提交补丁的注释中写道:“这个补丁展示了 eBPF 的潜力。”
BPF 不再局限于网络枝,已经成为内 核顶级的子系统。 BPF 程序架构强调安全性和稳定性,看上去更像内核模块,但与内核模块不同, BPF 程序不需要重新编译内核 , 并且可以确保 BPF 程序运行完成 ,而不会造成系统的崩溃。
架构
BPF 是一种高级虚拟机,可以在隔离的环境执行代码指令。
执行顺序:
C代码编译成BPF字节码
从某种意义上看, BPF 和 Java 虚拟机 ( JVM) 功能类似,我们可以将高级编程语言编译成机器代码, JVM 是一种运行这种机器代码的专用程序。编译器LLVM 和 GNU GCC (不久的将来) 可提供对 BPF 的支持,将 C 代码编译成 BPF 指令。
BPF 验证器
代码编译后, BP F 使用 BPF 验证器来确保程序在内核中安全运行。BPF 验证器能阻止可能使内核崩渍的代码。如果代码是安全的, BPF 程序将被加载到内核中。 Linux 内核也为 BPF 指令集成了即时编译器。
(即时编译又叫实时编译,是一种把字节码翻译成机器码并且缓存起来以降低性能耗损,被用来改善应拟机性能)字节码转机器码
在程序被验证后, JIT 编译器会直接将 BPF 字节码转换为机器代码,从而减少运行时的时间开销。该架构具有一个非常有用的特点就是加载 BPF 程序无
须重启系统,我们不仅可以在系统启动时通过初始化脚本加载 BPF 程序,也可以按需随时加载程序。
执行点:
(程序执行点是由 BPF 程序类型确定,我们将在第 2 章讨论它们)
在内核运行 BPF 程序之前,我们需要知道程序附加的执行点。内核中有诸多执行点,数量也在持续增长。当选择了特定的执行点时,内核会提供一些可用的帮助函数,这些帮助函数可用于处理程序接收的数据,从而使执行点和 BPF 程序能够紧密地配合。
BPF映射:
(BPF 映射负责在内核和用户空间之间共享数据。我们将在第 3 章中讨论 BPF 映射)
BPF 映射提供双向的数据共享,这意味着我们可以分别从内核和用户空间写入和读取数据。 BPF 映射包括一些数据结构类型,从简单数组、哈希映射到自定义的映射,我们甚至可以将整个 BPF 程序保存在 BPF 映射中。