共计 2744 个字符,预计需要花费 7 分钟才能阅读完成。
- 倒退溯源
回顾技术的倒退过程,就像观看非洲大草原日出日落一样,巨大的过程让人打动,细节局部引人深思。每天循环不辍,却又每天不同。
BPF 的利用早已超过了它最后的设计,但如果要追溯 BPF 最后的起源,则必须回归到它最后的应用领域,再进行了解剖析。
BPF 最后的用处在于观测,最后用于网络报文的抓取和剖析。
因而 BPF 的最后、最基本的起源,是作为一种观测伎俩呈现的。
而在这个畛域中,技术的演进迭代,是一个很长的过程,体现了内核技术倒退的艰苦、也同时充斥了趣味。
如果把内核看作一个世界,在这个广袤的土地上,观测技术的倒退,也同样经验了从蒙昧到古代的倒退过程。
每个时代都有其独具特色的观测技术,它决定了过后的开发人员须要具备什么样的功底,什么样的开发方式,这形成了一个时代特色,也谱写了时代的故事。
而每次时代的更迭,总是在某些方面颠覆了或者冲破了传统的思维,从而引发了观测形式的巨大进步,促成了效率和可观测性的晋升。对现有技术的深入研究与颠覆性的思维所形成的翻新,是技术畛域演进的根本模式。而其翻新的能源又是什么呢?咱们在后文逐渐揭示。
3.1 石器时代
曾几何时,内核的开发还在初始阶段,因为内核的原理简单、所处的地位非凡,开发方式和用户态有很大不同。内核开发难度远远大于用户态的利用开发,尤其调试比拟艰难。犹记得那时对于内核是否引入 GDB 调试机制,有过一些争执。其分歧点就在于,引入过于简单的机制会扭转内核的行为个性,影响问题的稳定性,反而不利于问题的剖析定位。
那时最值得信赖的工具就是 printk 了。这是一种低染指的观测工具,应用简略,简直能够用于任何中央,帮忙开发人员观测内核的运行状态。但显著的毛病是不够灵便,如果问题波及的逻辑门路比拟长、分支比较复杂的话,须要重复屡次能力定位问题的本源。因而,那时候对内核开发人员的一个必不可少的要求,就是对所负责子系统的实现原理和代码逻辑的相熟水平须要十分高,可能依据比拟少的观测信息,精确定位问题的本源。
事物总是存在两面性,就像当初产生的那场争执一样,printk 除了根本的信息输入机制外,简直没有提供任何强有力的个性,这诚然体现了过后的技术水平还在比拟原始的阶段(没错,就像是石器时代),但同时也倒逼过后的内核开发人员超强的代码了解和剖析能力。以便补救简陋的工具对效率的掣肘,更快地解决程序中的 BUG。
另一方面,主观地讲,printk 诚然简略,卓尔无往不利。它能够应用在任何中央,具备齐全的上下文拜访能力,不受约束的表达能力。
它的观测能力和程序自身齐全相等,程序自身能看到什么它就能看到什么,能够说是弱小到巅峰。
这种弱小也是其无奈被取代的根本原因,只管内核的调测技术一直在倒退,这一点始终未被超过。
它能够用任何线性的文本模式,输入开发人员关注的上下文信息。在起初,这种表达能力失去了进一步倒退,反对了局部正则文法。
它的毛病在于不足交互性,任何一点扭转都须要批改程序。另一方面,不论下层流程是否被关注,它的信息都会被输入,大大影响了性能。
printk 能够说是最弱小的工具,至今我也是这样认为。但它同时也是最毛糙的工具。就像石头一样,prink 随处可见,随处可用,用了就肯定有所得。简略、弱小、间接。然而同样像石头一样,如果用得多了,就会成为垃圾。
printk 相比于 BPF,领有齐全不受限制的上下文拜访能力,应用的中央简直没有限度,仅从观测的角度,弱小之处有过之而无不及。然而应用形式过于原始,不足工业化的扩大能力,因而如果在更长的时间尺度、更广的应用领域来看的话,printk 无奈和 BPF 等量齐观。
3.2 铁器时代
在石器时代,人们应用石头磨制的工具进行生产,这些工具毛糙、非标准化、材质原始容易损坏,轻便、应用寿命短。
Printk 也是一样,每次执行时都会输入信息,但大多数时候是不须要的;寿命短,每次扭转须要批改代码。
随着内核越来越成熟,架构设计、模块划分、外部性能等等都越来越标准正当。内核的个性,由各个子系统别离负责,内核的整体体现是各个子系统行为表现的综合。而子系统外部的要害门路,决定了子系统次要的行为表现,比方:调度零碎中的 CPU 工夫统计、上下文切换,迁徙等等;内存管理系统中的内存调配、NUMA 均衡;虚拟内存中的页面谬误、替换次数等等。
随着内核设计的规范化,其外部的要害节点和出现在内部的语义都越来越清晰和标准化。要把握内核的运行状态,其实并不需要随处察看,只须要把握几个要害节点、要害信息就能够了。
以要害变量为根底,工具得以降级;以语义规范化为根底,为交互式的观测机制提供了根底。至此,观测伎俩不再是单纯的信息输入,它也能够反过来影响零碎行为实现多维度的观测。
虚构文件系统 Proc 首先买通了用户态和内核态的交互通道,从原来只能管制日志级别,到能够控制数据自身,能够管制的范畴更广、更深了;从文本交互,转换为二进制交互,内核性能受到的影响进一步升高。
提供了标准化的 API,类型的反对,升高了开发难度,便于推广应用。
提炼出要害参数,通过虚构文件系统进行交互式的零碎观测,反过来有利于内核的规范化。
3.3 蒸汽时代
Proc 的定义很大一部分,还是与具体的上下文相干,并不适宜大批量的应用。
Trace 定义了协定标准,抽象层次更高,能够批量应用。
Trace 是一个更加纯正的观测机制,给用户提供了通用简略的接口,底层实现了很丰盛的机制。能够反对大量应用,对于可观测性的晋升起到了根本性的推动。能够批量重复使用,这是它和其余观测形式的区别。
如果说 Proc 采纳了代码数据化的思维,那么 Trace 采纳很多元编程的思维,极大简化了内部接口,缩小了反复代码。
3.4 电气时代
Trace 机制诚然好用,只有事后铺设了基础设施,运行时就能够随时开启观测。但毛病是,对于没有铺设铁轨的中央,火车的承载能力再强也是无奈达到的。
Trace 的机制很通用,但另一方面,它无奈深刻业务层面进行更进一步的调测。要实现这一点,须要残缺的上下文能力和可编程能力,因而 kprobe 呈现了。
只有由函数的中央,就像通了电一样,随时能够点亮,这是 Kprobe 强于 Trace 的笼罩能力。可能残缺拜访函数上下文,这是 Kprobe 强于 Trace 的业务理解能力。
3.5 智能时代
Kprobe 是动态性的萌芽,然而很多方面有余。它在内核态运行,须要对内核编程有肯定理解,编程门槛较高。它有安全性问题,它还有可扩展性问题,等等。
从计算能力来说,所有图灵机的计算能力是相等的,要解决能力问题,最终是要实现一个虚拟机的。而在内核态实现一个虚拟机,所波及到的平安问题是必须思考的,通过 Verifier 和运行时 Helper 函数,做到了逻辑束缚和上下文隔离。虚拟机、Verifier 和 Helper 函数,是 BPF 和 Kprobe 的基本区别。