《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言

1.1BPF和eBPF是什么

probe n.探针,探头
在生产环境中可以立刻部署BPF跟踪程序,不需要重启系统,也不需要以特殊方式重启应用软件。直接在生产环境中进行现场直播。
下图是针孔摄像探头:
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第1张图片

Brendan Gregg 布伦丹·格雷格
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第2张图片

Alexei Starovoitov
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第3张图片
Daniel Borkmann丹尼尔·博克曼
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第4张图片

BPF是Berkeley Packet Filter ( 伯克利数据包过滤器 )的缩写,这项冷门技术诞生于1992年,其作用是提升网络包过滤工具的性能。
2013 年,Alexei Starovoitov向Linux社区提交了重新实现BPF的内核补丁,经过Alexei Starovoitov和Daniel Borkmann的共同完善,相关工作在2014年正式并入Linux内核主线。
此举将BPF变成了一个更通用的执行引擎,其可以完成多种任务,包括用来创建先进的性能分析工具。

简单来说,BPF提供了一种在各种内核事件和应用程序事件发生时运行一段小程序的机制。
如果你熟悉JavaScript,可能会看到一些相似之处: JavaScript 允许网站在浏览器中发生某事件(比如鼠标单击)时运行一段小程序,这样就催生了各式各样基于Web的应用程序。
BPF则允许内核在系统和应用程序事件(如磁盘IO事件)发生时运行一段小程序,这样就催生了新的系统编程技术。
该技术将内核变得完全可编程,允许用户(包括非专业内核开发人员)定制和控制他们的系统,以解决现实问题。

BPF是一项灵活而高效的技术,由指令集、存储对象和辅助函数等几部分组成。
由于它采用了虚拟指令集规范,因此也可将它视作一种虚拟机实现。
这些指令由Linux内核的BPF运行时模块执行,具体来说,该运行时模块提供两种执行机制: 一个解释器和一个将BPF指令动态转换为本地化指令的即时(JIT) 编译器 。在实际执行之前,BPF指令必须先通过验证器(verifer) 的安全性检查,以确保BPF程序自身不会崩溃或者损坏内核(当然这不会阻止最终用户编写出不合逻辑的程序一那些虽可执行但没意义的程序)。
BPF的具体组成部分详见第2章。

目前BPF的三个主要应用领域分别是网络、可观测性和安全。 本书主要关注可观测性(跟踪)。

扩展后的BPF通常缩写为eBPF ,但官方的缩写仍然是BPF,不带“e”,所以在本书中,笔者用BPF代表扩展后的BPF。事实上,在内核中只有一个执行引擎,即BPF (扩展后的BPF),它同时支持扩展后的BPF和“经典”的BPF程序。‘

1.2 跟踪、嗅探、采样、剂析和可观测性分别是什么

这些全都是用来对分析技术和工具进行分类的术语。

跟踪(tracing) 是基于事件的记录一一这也是BPF工具所使用的监测方式。
你可能已经使用过一些特定用途的跟踪工具。例如,Linux下的strace(1),可以记录和打印系统调用(system call)事件的信息。
有许多工具并不跟踪事件,而是使用固定的计数器统计监测事件的频次,然后打印出摘要信息;Linux top(1)便是这样的一个例子。
跟踪工具的一个显著标志是,它具备记录原始事件和事件元数据的能力。但是这类数据的数量不少,因此可能需要经过后续处理生成摘要信息。
BPF技术,催生了可编程的跟踪工具的出现,这些工具可以在事件发生时,通过运行一段小程序来进行定制化的实时统计摘要生成或其他动作。

strace(1)的名字中有“trace” (跟踪)字样,但并非所有跟踪工具的名字中都带“trace”。例如,tcpdump(8) 是一个专门用于网络数据包的跟踪工具。(也许它应该被命名为tcptrace ? ) Solaris操作系统有它自己的tcpdump版本,称为snoop(1M) (嗅探器) ;之所以起这个名字,是因为它是用来嗅探网络数据包的。 笔者(Brendan Gregg )先前在Solaris系统上开发和发布了许多跟踪工具,在那里我(有一丝后悔)普遍使用了“嗅探器(snoop)”来命名那些工具 。这也是为什么现在会有下面这些工具: execsnoop(8). opensnoop(8)、biosnoop(8)等。 嗅探、事件记录和跟踪,通常指的是一回事
这些工具将在后面的章节中加以介绍。

除了工具的名称,“tracing”一词也经常用于描述将BPF应用于可观测性方面的用途。Linux内核开发人员尤其喜欢这么表达。

采样(sampling)工具通过获取全部观测量的子集来描绘目标的大致图像;这也被称作生成性能剖析样本或profiling 。有一个BPF工具就叫profile(8),它基于计时器来对运行中的代码定时采样。例如,它可以每10毫秒采样一次,换句话说,它可以每秒采样100次(在每个CPU上)。采样工具的一个优点是,其性能开销比跟踪工具小,因为只对大量事件中的一部分进行测量。采样的缺点是,它只提供了一个大致的画像,会遗漏事件。

可观测性(observability) 是指通过 全面观测来理解一个系统,可以实现这一目标的工具就可以归类为可观测性工具。 这其中包括跟踪工具、采样工具和基于固定计数器的工具。但不包括基准测量(benchmark)工具,基准测量工具在系统上模拟业务负载,会更改系统的状态。本书中的BPF工具就属于可观测性工具,它们使用BPF技术进行可编程型跟踪分析。

1.3BCC、bpftrace 和 IO Visor

直接通过BPF指令编写BPF程序是非常烦琐的,因此我们开发了可以提供高级语言编程支持的 BPF前端 ;在跟踪用途方面,主要的前端是BCC和bpftrace。

BCC (BPF编译器集合,BPF Compiler Collection)是最早用于开发BPF跟踪程序的高级框架。 BCC提供了一个编写内核BPF程序的C语言环境,同时还提供了其他高级语言(如Python、Lua和C++ )环境来实现用户端接口它也是libbcc和libbpf库的前身,这两个库提供了使用BPF程序对事件进行观测的库函数。BCC源代码库中提供了70多个BPF工具,可以用来支持性能分析和排障工作。 你可以在自己的系统上安装BCC, 无须自己动手编写任何BCC代码,直接运行其提供的现成工具即可。本书会带领你了解和使用这些工具。

bpftrace是一个新近出现的前端, bpftrace提供了专门用于创建BPF工具的高级语言支持。bpftrace工具的源代码非常简洁,因此本书中介绍相关工具时,可以直接带上源代码来展示具体的观测操作以及数据是如何被处理的。 bpfrace也是基于libbecc和libbpf库进行构建的。

图1-1展示了BCC和bpftrace。BCC和bpftrace具有互补性:bpftrace在编写功能强大的单行程序、短小的脚本方面甚为理想;BCC则更适合开发复杂的脚本和作为后台进程使用,它还可以调用其他库的支持。比如,有不少用Python开发的BCC程序,它们使用Python的argparse库来提供复杂、精细的工具命令行参数支持。

还有一个叫作ply的BPF前端,目前处在开发阶段。它的设计目标是尽可能轻量化并且将依赖最小化,因此尤其适合在嵌入式Linux环境下使用。如果ply比bpftrace更适合你的需求,你仍然会发现本书对于了解如何使用BPF开展分析工作十分有用。本书中有数十个bpftrace工具,在转化为ply的语法格式后就可以使用ply执行(ply 的后续版本也许会直接支持bpfrace语法)。本书选择bpftrace, 是因为它相对更加成熟,而且有我们分析全部目标所需要的全部特性。
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第5张图片
BCC和bpftrace不在内核代码仓库中,而是属于 GitHub上的一个名为IO Visor的Linux基金会项目 。它们的源代码仓库可参见链接 2:
链接2.1
链接2.2

在本书中使用“BPF跟踪”术语时,同时包括BCC和bpftrace版本的工具。

1.4 初识BCC:快速上手

让我们直接切入主题,快速上手来看一些工具的输出吧。下面这个execsnoop(8)工具会跟踪每个新创建的进程,并且为每次进程创建打印一行信息。 这个叫execsnoop(8) 的工具来自BCC项目,它通过跟踪execve(2)系统调用来工作。execve(2)是exec(2)系统调用的一个变体(也因而得名)。第4章会介绍BCC工具的安装,再往后的章节会更详细地介绍相关工具。

《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第6张图片
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第7张图片
上面的输出显示了在执行跟踪的过程中,系统创建了哪些进程:其中有些进程运行时间太短,因而使用其他工具可能无法捕获到相关信息。在输出中都能看到大量标准的UNIX工具: ps(1)、grep(1)、sed(1)、cut(1)等。但是在这里你无法看到这个命令的打印速度。 execsnoop(8)带上命令行参数-t后,会增加一列时间戳输出:
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第8张图片
上述输出进行了截断(用[…]表示),但时间戳那列信息还是显示了一个新的线索:新进程的批量创建之间有1秒的间隔,而且这个模式不断重复。通过浏览输出可以发现,每秒会批量创建30个新的进程,然后 停顿1秒,继续批量创建30个新的进程。

上述输出结果取自笔者在Netfix公司调查真实性能问题时使用execsnoop(8)的过程。这台服务器的作用是进行微基准测试,但问题是每次基准测试的结果差异很大,影响了可信度。笔者在系统空闲时运行了execsnoop(8),事实证明并非如我所想!每秒都有很多进程被创建出来,这些进程对基准测试造成了干扰。 最终,我们发现,因为有一个服务的配置不正确,导致它每秒都会被拉起、失败,然后再被拉起,如此反复。当把这个服务彻底禁止之后,就没有新的进程被创建出来了(同样可以使用execsnoop(8) 进行验证),基准测试的数值也稳定了下来。

execsnoop(8)的输出可以用来辅助支撑一个性能分析方法论:业务负载画像( workload characterization),本书中涉及的其他BPF工具的功能也都支持该方法论。 业务负载画像方法论其实很简单,就是给当前业务负载定性。定性是指通过非量化的手段来探究事物的本质 。理解了业务负载,很多时候就足够解决问题了,这避免了深入分析延迟问题,也不需要进行下钻分析(drill-down analysis)。在本案例中,业务负载就是这些不断有进程的创建。第3章会详细介绍该方法论以及其他的分析方法论。请你尝试在自己的系统上运行execsnoop(8),并且让它运行1小时,看看是否有所发现?

一、业务负载画像
找出实际运行的业务负载进行分析,具体内容:
1、WHO:负载是谁产生的?比如:进程ID、用户ID、进程名、IP地址。
2、WHY:负载为什么会产生?比如:代码路径、调用栈、火焰图。
3、WHAT:负载的组成是什么?比如:IOPS、吞吐量、负载类型。
4、HOW:负载怎么样随着时间发生变化?比如:比较每个周期的摘要信息。
二、下钻分析
从一个指标出发,然后将这个指标拆分成多个组件,将最大的组件进一步拆分为更小的组件,不断重复这个过程,直到定位出一个或多个原因。具体步骤:
1、从业务最高层级开始分析。
2、检查下一个层级的细节。
3、挑出最感兴趣的部分或者线索。
4、如果问题还没有解决,跳转至第2步。

execsnoop(8)会在每个进程创建时打印信息,而其他 一些BPF工具则可以高效地计算摘要统计信息 。另一个可以快速上手的工具是biolatency(8),它可以绘制块设备I/O(diskI/O)的延迟直方图。

下面是在一台生产环境中的数据库服务器上运行biolatency(8) 的输出,该数据库对延迟非常敏感,因为该服务的服务质量目标( service level agreement)只有几毫秒。
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第9张图片
当biolatency(8)工具运行时会监测块I/O事件,它们的延迟信息通过BPF程序进行计算和统计。当工具停止执行后(用户按下Ctrl+C组合键),摘要信息就被打印出来了。笔者使用了命令行参数-m来使得统计值以毫秒为单位输出。

上面的输出结果中有一些有趣的细节:它呈现了双峰分布特征,并且显示了延迟离群点的存在。第一峰(图中用ASCII字符展示)是0~ 1毫秒这个区间,在跟踪时有共计16335个I/O事件。这个速度相当快,可能是因为命中了存储设备上的缓存或者使用的是闪存设备。第二峰是32~ 63毫秒这个区间,这相对此类存储设备的预期性能慢了不少,意味着可能有排队发生。可以用更多的BPF工具深入调查进行确认。最后,对于512~ 1023毫秒区间,有11个I/O事件。这些极大的延迟称为 延迟离群点 。现在我们1.5 BPF跟踪的能见度

知道了有这样的离群点存在,后面就可以使用其他BPF工具来进一步定位。 对于数据库团队,这是需要高优先级研究和解决的问题,因为一旦数据库阻塞在了这些I/O请求上,数据库的延迟服务质量承诺就无法达到了。

1.5 BPF跟踪的能见度

BPF跟踪可以在整个软件栈范围内提供能见度,允许我们随时根据需要开发新的工具和监测功能。在生产环境中可以立刻部署BPF跟踪程序,不需要重启系统,也不需要以特殊方式重启应用软件。这感觉有点像医学检查使用的X光影像:当需要对某些内核组件、设备、应用库进行检查时,我们能够以一种前所未有的方式看到它们的内部运作—— 直接在生产环境中进行现场直播。

为了更好地说明问题, 图1-2展示了一个通用的系统软件栈,笔者用相应的BPF性能工具对各个部分进行了标记。一目了然工具覆盖全了系统 。这些工具有的来自BCC,有的来自bpftrace,还有的来自本书。它们中的大部分会在后续章节中加以介绍。
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第10张图片
请你思考一下,你会使用哪些工具来检查诸如内核CPU调度器、虚拟内存,以及文件系统等组件?只需简单浏览这张图,你就可以发现先前分析领域的盲区,现在BPF工具都覆盖到了。

表1-1列出了传统工具,同时也列出了BPF工具是否支持对这些组件进行监测。
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第11张图片
传统工具提供的信息可以作为性能分析的起点,后续则可以通过BPF跟踪工具做更加深入的调查。第3章总结了如何利用系统工具进行基础性能分析,你可以将其作为工作的起点。

1.6动态插桩: kprobes 和uprobes

BPF跟踪支持多种事件源,可以在整个软件栈的范围内提供能见度。其中值得专门一提的是动态插桩技术(也叫动态跟踪技术)——在生产环境中对正在运行的软件插入观测点的能力。 在未启用时,软件不受任何影响,动态插桩的开销为零。BPF 工具经常使用动态插桩技术,在内核函数或应用函数的开始或结束位置进行插桩。具体被插桩的函数可以是软件栈中成千上万的运行函数中的任意一个。BPF提供的能见度是如此深入和彻底,给人的感觉就像是一种超能力。

动态插桩技术最早出现在1990 年代Holniwortngr,基于调试器( debugger)用来给程序的任意指令地址插入断点的技术。 和调试器不同的是,动态插桩技术在软件记录完信息后自动继续执行,而不是把程序的控制交给调试器。 有人开发了动态跟踪工具(比如kerninstCambhs99l), 其也包含相应的跟踪语言,但是这些工具实在太过复杂,在实践中很少被使用,还有部分原因是它们会带来较大的运行风险:动态跟踪要求实时修改地址空间中的应用指令,一旦出现任何错误就会导致进程或者内核崩溃。

Linux系统中的第一个动态插桩技术实现,是一个IBM团队在 2000年 开发的 DProbes 技术,不过当时社区最终拒绝了将相关补丁并入内核。源自DProbes的对内核函数的动态插桩(kprobes), 最终于 2004 年正式进入内核,但是此时该技术仍然不太为人所知而且很难使用。

2005年情况发生了重大变化。当年Sun (Sun Microsystems)公司发布了它自己的动态跟踪技术DTrace,以及与之匹配且易用的D语言,并且集成到了Solaris 10操作系统中。Solaris 系统向来以生产环境下的稳定性著称,而且DTrace作为默认配置安装也帮助证明了动态跟踪技术可以在生产环境中安全使用。这成为这项技术的拐点。笔者曾经发表了多篇文章介绍运用DTrace工具解决现实问题的案例,也发布了多个DTrace工具。Sun公司的市场和销售部门也不遗余力地宣传这项技术,将它视作一项关键的具有竞争力的特性。Sun 公司的教培服务(Sun Educational Services)将DTrace引入Solaris系统的标准教程之中,并且提供了专门的DTrace课程。所有这些努力使得动态插桩技术从一项艰深难用的技术,华丽转身为一个为人所熟知并且令人期待的特性。

2012年 ,Linux 以uprobes形式增加了对用户态函数的动态插桩支持。BPF跟踪工具既支持kprobes又支持uprobes,因而也就支持对整个软件栈进行动态插桩。

为了展示动态跟踪是如何使用的,表1-2列举了一些bpfrace所 使用的uprobes和kprobes探针定义 (probe specifer)的例子。(bpftrace 将在第5章详加介绍。)
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第12张图片

1.7静态插桩: tracepoint 和USDT

动态插桩技术有一点不好:随着软件版本的变更,被插桩的函数有可能被重新命名,或者被移除。 这属于接口稳定性问题。当对内核或者应用软件升级之后,可能会出现BPF工具无法正常工作的情况。某些工具可能会打印一些错误信息,表明它无法找到特定函数,还有一些工具可能根本不会有任何输出。另一个问题是编译器可能会启用优化,将某些函数做内联(inline) 处理,这就使得这些函数无法使kprobes 或uprobes动态插桩。

对于稳定性问题和内联问题,有一个统一的解决办法,那就是改用静态插桩技术 。静态插桩会将稳定的事件名字编码到软件代码中,由开发者进行维护。BPF跟踪工具支持内核的静态跟踪点插桩技术,也支持用户态的静态定义跟踪插桩技术USDT(userlevel statically defined tracing)。静态插桩技术也有美中不足:插桩点会增加开发者的维护成本,因此即使软件中存在静态插桩点,通常数量也十分有限。

上面提到的这些细节,除非需要开发自己的BPF工具,一般不需要关注。如果确实需要开发,一个推荐的策略是,首先尝试使用静态跟踪技术(跟踪点或者USDT),如果不够的话再转而使用动态跟踪技术(kprobes 或uprobes)。

表1-3列举了一些在bpfrace中 使用跟踪点和USDT的探针定义的例子 。表中提到的open(2)跟踪点可以参见1.8节。
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第13张图片

1.8初识pbftrace: 跟踪open()

我们来用bpfrace跟踪系统调用open(2)作为开始吧。
可以使用一个现有的静态插桩点(syscall:sys _enter _open), 笔者将在命令行中写一个短小的bpftrace程序,即一个单行程序(one-liner)。

不要求你此刻就理解下面单行程序的代码,bpftrace语言和安装操作说明是第5章的内容。不过在这里,你应该可以猜到该程序做了什么事情,因为它是非常直观的(直观的语言通常意味着其背后经过了精心设计)。此刻,我们只需关注输出结果:
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第14张图片
在这里插入图片描述
输出结果打印了进程的名字 和 传递给open(2)系统调用的文件名 :bpfrace是全系统层面的跟踪,因此任何调用了open(2) 的应用都能覆盖。 输出结果的每一行代表一次系统调用,这也是输出单个事件的工具的例子。 BPF跟踪技术不仅用于生产环境下对服务器的分析。例如,就在笔者使用笔记本电脑写书的此时此刻,正在用BPF工具观察聊天软件Slack正在打开什么文件。

BPF程序被定义在单引号所包围的代码内,当敲击Enter 键运行bpfrace命令时,它会立即被编译并且运行。而当按下Ctrl+C组合键结束命令执行时,open(2) 的跟踪点就被禁用了,相应地,BPF 小程序也会被移除。这就是BPF跟踪工具提供的按需插桩的工作方式:它们只在相关命令的存活期间被激活,观测时间可以短至几秒。

输出结果的时间比笔者预想的要慢,这里可能是因为遗漏了一些open(2)系统调用事件。内核支持一些open系统调用的变体,上面只跟踪了其中的一个。可以通过为bpfrace的命令行加参数-1和通配符的方式, 列出所有的与open系统调用相关的跟踪点。
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第15张图片
不过,openat(2) 这个open的变体现在使用的频率可能更高。接下来我们可以使用另一个bpfrace单行程序来验证这一点:
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第16张图片
和前面一样,此小程序的代码会在第5章进行解释,此刻只需理解输出结果就可以了。这次的输出结果展示了跟踪点的统计结果,而没有每次事件打印一行。这个结果确认了,openat(2)系统调用被调用的次数确实更多一308 次,而open(2)系统调用仅被调用了5次。这个摘要信息是由BPF程序在内核中高效地计算出来的。

现在可以在单行程序中添加第2个跟踪点,这样可以同时跟踪open(2)和openat(2) 。然而,单行程序开始变得有点长了,在命令行下使用不是那么方便。此时更好的方式是将单行程序保存在一个 脚本 (可执行文件)中,这样就可以方便地使用文本编辑器编辑程序。实际上已经有现成的工具了: bpfrace自带了 opensnoop.bt , 这个工具可以同时对每个系统调用的开始和结束位置进行跟踪,然后将结果分列输出:
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第17张图片
这里的列信息包括进程ID (PID)、 进程命令名字(COMM)、文件描述符(FD).错误代码(ERR),还有系统调用试图打开的文件的路径(PATH)。opensnoop.bt 工具可以对出错的软件进行故障排查,也许软件尝试打开了错误的文件位置:也可以用于了解配置和日志文件的具体位置:还可以识别一些性能问题,比如文件打开频次过快,或者反复检查错误文件位置等。这个工具的用途十分广泛。

共有20多个这样的现成工具随bpfrace一同发布,BCC则自带超过70个工具。这些工具除了可以帮助我们快速定位问题,同时提供源代码以展示如何跟踪各种类型的目标事件。正如我们在前面跟踪open(2)时看到的那样, 有时使用这些事件会出状况,可以通过工具源代码来找到解决方案。

1.9再回到BCC: 跟踪open()

现在我们来看一下BCC版本的opensnoop(8):
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第18张图片
这里的输出和之前的单行程序的输出内容非常相似——至少它们具有一致的列字段。 不过BCC版本的opensnoop(8)比pbftrace版本支持更多的输出内容,执行时可以带不同的命令行参数 :
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第19张图片
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第20张图片
bpfrace工具通常比较简单,功能单一,只做一件事情; BCC工具则一般比较复杂,支持的运行模式也比较多。比如你可以通过修改bpfrace版本的opeenssncop工具只显示失败的open系统调用,而BCC版本则通过命令行参数(-x)直接支持了这一功能:
《BPF( 伯克利数据包过滤器 ) Performance Tools》 第一章 引言_第21张图片
上述输出显示了不断重复的打开失败操作。这种错误模式可能指向程序中的效率问题,或者是某种可以被修复的配置错误。

BCC工具通常会支持多个命令行参数,它们可以改变工具的行为,这让BCC工具比bpfrace工具的功能更多样化。 这也让BCC工具更加适合作为工作的起点:不必动手编写任何BPF程序,你所需要的功能可能都已经自带了 不过,如果确实还缺少你所需的功能,那可以用bpfrace来定制工具,因为bpftrace语言开发相对更加简单。

bpftrace工具可以后续改写为功能更加复杂、支持多种命令行参数的BCC工具,比如之前展示的opensnoop(8)工具。 BCC工具也可以支持同时使用不同的事件 ,比如优先使用跟踪点, 如果条件不满足再转而使用动态插桩kprobes 。但是请注意,BCC编程的复杂度要高很多,本书没有涉及相关内容。本书的关注点是bpfrace编程。附录C提供了使用BCC工具进行开发的快速入门课程。

你可能感兴趣的:(《BPF,Performance,Tools》读书笔记,前端,服务器,运维)