Bpftrace 的全面介绍

2021-08-10 01:19:26

bpftrace 是一个新的 Linux 开源跟踪器,用于分析生产性能问题和故障排除软件。许多公司都在使用它,包括 Netfilx、Facebook、Red Hat、Shopify 等。它由 Alastair Robertson 创建,Alastair Robertson 是一位才华横溢的英国开发人员,曾在各种编码比赛中获胜。 Linux 已经有许多性能工具,但这些工具通常是基于计数器的并且可见性有限。例如,iostat(1) 或监控代理可能会告诉您平均磁盘延迟,但不会告诉您此延迟的分布。分布可以揭示多种模式或异常值,其中任何一种都可能是导致性能问题的真正原因。 bpftrace 适用于这种分析:将指标分解为分布或每个事件的日志,并创建新的指标以了解盲点。您可以通过单行程序或脚本使用 bpftrace,它附带了许多预先编写的工具。这是一个示例屏幕截图:跟踪 PID 181 的读取延迟分布,并将其显示为 2 的幂直方图:# bpftrace -e 'kprobe:vfs_read /pid == 30153/ { @start[tid] = nsecs ; }kretprobe:vfs_read /@start[tid]/ { @ns = hist(nsecs - @start[tid]);删除(@start[tid]); }'附加2个探针...^C@ns:[256, 512) 10900 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |[512, 1k) 18291 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@|[1k, 2k) 4998 |@@@@@@@@@@@@@@|[2k, 4k) 57 | |[4k, 8k) 117 | |[8k, 16k) 48 | |[16k, 32k) 109 | |[32k, 64k) 3 | |此示例检测了数千个可用事件之一。如果您遇到一些奇怪的性能问题,可能有一些 bpftrace one-liner 可以解决这个问题。对于大型环境,此功能可以帮助您节省数百万美元。对于较小的环境,它可以更有用地帮助消除延迟异常值。我之前写过关于 bpftrace 与其他跟踪器的文章,包括 BCC(BPF 编译器集合)。 BCC 非常适合罐装的复杂工具和代理。 bpftrace 最适合短脚本和临时调查。在这篇文章中,我将总结 bpftrace 语言、变量类型、探针和工具。 bpftrace 使用 BPF(伯克利数据包过滤器),这是一种处理虚拟指令集的内核执行引擎。近年来,BPF 得到了扩展(又名 eBPF),以提供一种安全的方式来扩展内核功能,并已成为系统工程中的热门话题,在上届 Linux Plumber 会议上至少有 24 场关于 BPF 的演讲。 BPF 在 Linux 内核中,bpftrace 是开始使用 BPF 进行可观察性的最佳方式。

有关如何安装它,请参阅 bpftrace INSTALL 指南,并获取最新版本:0.9.1 刚刚发布。对于 Kubernetes 集群,还有用于运行它的 kubectl-trace。探针指定要检测的事件,过滤器是可选的,可以根据布尔表达式过滤事件,动作是运行的小程序。探针是 BEGIN,一个特殊的探针,它运行在程序的开头(如 awk)。没有过滤器。该操作是一个 printf() 语句。这使用 kretprobe 来检测 sys_read() 内核函数的返回。如果 PID 是 181,一个特殊的映射变量 @bytes 被填充一个 log2 直方图函数,返回值是 sys_read()。这会生成 PID 181 的返回读取大小的直方图。您的应用程序是否进行了大量 1 字节读取?也许可以优化。这些是相关的探针库。当前支持的类型是(将添加更多类型): 如果您不熟悉这个术语:动态检测(又名动态跟踪)是一种超能力,它使您无需重新启动即可跟踪正在运行的二进制文件中的任何软件功能。这可以让您深入了解任何问题。但是,它公开的函数不被视为稳定的 API,因为它们可以从一个软件版本更改为另一个软件版本。因此静态检测,其中事件点被硬编码并成为稳定的 API。写bpftrace程序时,尽量先用静态类型,再用动态类型,这样你的程序会更稳定。带有“@”前缀的变量使用 BPF 映射,其行为类似于关联数组。它们可以通过以下两种方式之一进行填充:

学习 bpftrace 的一个好方法是通过 one-liners,我把它变成了 one-liners 教程。该教程涵盖以下单行: 1. 列出探针 bpftrace -l 'tracepoint:syscalls:sys_enter_*'2。 Hello world bpftrace -e 'BEGIN { printf("hello world\n") }'3.文件打开 bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("%s %s\n", comm, str(args->filename)) }'4.系统调用按进程 bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count() }'5. read() 字节的分布 bpftrace -e 'tracepoint:syscalls:sys_exit_read /pid == 18644/ { @bytes = hist(args->retval) }'6. read() 字节的内核动态跟踪 bpftrace -e 'kretprobe:vfs_read { @bytes = lhist(retval, 0, 2000, 200) }'7.计时 read()s bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs } kretprobe:vfs_read /@start[tid]/ { @ns[comm] = hist(nsecs - @start[tid]);删除(@start[tid]) }'8.计数进程级事件 bpftrace -e 'tracepoint:sched:sched* { @[name] = count() } interval:s:5 { exit() }'9.配置 CPU 内核堆栈 bpftrace -e 'profile:hz:99 { @[stack] = count() }'10.调度程序跟踪 bpftrace -e 'tracepoint:sched:sched_switch { @[stack] = count() }'11.块 I/O 跟踪 bpftrace -e 'tracepoint:block:block_rq_complete { @ = hist(args->nr_sector * 512) }' 除了单行程序,bpftrace 程序还可以是多行脚本。 bpftrace 附带了其中 28 个作为工具: tools# ls *.btbashreadline.bt dcsnoop.bt oomkill.bt syncsnoop.bt vfscount.btbiolatency.bt execsnoop.bt opensnoop.bt syscount.bt vfsstat.btbiosnoop.btper get bt tcpaccept.bt writeback.btbitesize.bt killsnoop.bt runqlat.bt tcpconnect.bt xfsdist.btcapable.bt load.bt runqlen.bt tcpdrop.btcpuwalk.bt mdflush.bt statsnoop.bt 与他们的性能使用 tdiagnosbtrans 使用问题和一般故障排除,它们还提供了另一种学习 bpftrace 的方法:通过示例。 tools# cat -n biolatency.bt 1 /* 2 * biolatency.bt 块 I/O 延迟作为直方图。 3 * 对于 Linux,使用 bpftrace、eBPF。 4 * 5 * 这是同名 bcc 工具的 bpftrace 版本。 6 * 7 * 版权所有 2018 Netflix, Inc. 8 * 根据 Apache 许可证获得许可,版本 2.0(“许可证”)9 * 10 * 2018 年 9 月 13 日 Brendan Gregg 创建了这个。 11 */ 12 13 BEGIN 14 { 15 printf("Tracing block device I/O... Hit Ctrl-C to end.\n"); 16 } 17 18 kprobe:blk_account_io_start 19 { 20 @start[arg0] = nsecs; 21 } 22 23 kprobe:blk_account_io_done 24 /@start[arg0]/ 25 26 { 27 @usecs = hist((nsecs - @start[arg0]) / 1000); 28 删除(@start[arg0]); 29 } 30 31 END 32 { 33 清除(@start); 34 } 它简单易读,而且足够简短,可以包含在幻灯片中。此版本使用内核动态跟踪来检测 blk_account_io_start() 和 blk_account_io_done() 函数,并将它们之间以 arg0 为键的时间戳传递给每个函数。 kprobe 上的 arg0 是该函数的第一个参数,对于这些参数是 struct request *,其内存地址用作唯一标识符。

*_example.txt 文件中还提供了这些工具的屏幕截图,我在其中准确解释了我们所看到的内容。例如:tools# more biolatency_example.txtDemolatency of biolatency,Linux BPF/bpftrace 版本。这会跟踪块 I/O,并将延迟显示为 2 的幂直方图。例如:# biolatency.btAttaching 3 probes...Tracing block device I/O...按Ctrl-C 结束。^C@usecs:[256, 512) 2 | |[512, 1K) 10 |@ |[1K, 2K) 426 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@|[2K, 4K) 230 |@@@@@@@@@@@@@@@@@@@@@@@ @@@@@ |[4K, 8K) 9 |@ |[8K, 16K) 128 |@@@@@@@@@@@@@@@ |[16K, 32K) 68 |@@@@@ @@@ |[32K, 64K) 0 | |[64K, 128K) 0 | |[128K, 256K) 10 |@ |跟踪时,这表明 426 块 I/O 的延迟在 1K 到 2Kusecs(1024 到 2048 微秒)之间,在 1 到 2 毫秒之间。还有两种模式可见,一个在 1 到 2 毫秒之间,另一个在 8 到 16 毫秒之间:这听起来像是缓存命中和缓存未命中。还有 10 个 I/O 延迟为 128 到 256 毫秒:异常值。其他工具和仪器,如 biosnoop.bt,可以更清楚地了解这些异常值。[...] 有时在尝试理解这些工具时直接切换到示例文件是最有效的,因为输出可能是不言而喻的(按设计!)。在 /man/man8 下还有每个工具的手册页。它们包括关于输出字段的部分,以及工具的预期开销。 # nroff -man man/man8/biolatency.8biolatency(8) 系统管理员手册 biolatency(8)NAME biolatency.bt - 块 I/O 延迟作为直方图。使用 bpftrace/eBPF.SYNOPSIS biolatency.btDESCRIPTION 该工具将块设备 I/O(磁盘 I/O)中花费的时间(延迟)总结为 2 的幂直方图。这允许研究分布,包括模式和异常值。通常有两种模式,一种用于设备缓存命中,另一种用于缓存未命中,可以通过此工具显示。延迟异常值也将显示。[...] 编写所有这些手册页是开发这些工具中最不有趣的部分,在某些情况下,编写工具的时间比开发工具所需的时间长,但很高兴看到最终结果.由于 eBPF 已经合并到内核中,所以大部分工作都放在 BCC 前端,它提供了一个 BPF 库和 Python、C++ 和 lua 接口来编写程序。我已经在 BCC/python 中开发了很多工具,虽然在 BCC 中编码很冗长,但效果很好。如果您正在解决性能问题,bpftrace 更适合您拥有的所有一次性自定义查询。如果您正在编写具有许多命令行选项的工具或使用 Python 库的代理,您将需要考虑使用 BCC。

以下是 Netflix 将如何使用这些:在性能团队中,我同时使用两者:BCC 用于开发其他人可以轻松使用的罐头工具,以及用于开发代理;和 bpftrace 用于临时分析。比如说,在网络工程团队中,他们一直在使用 BCC 来开发满足他们需求的代理。安全团队最感兴趣的是 bpftrace,它可以快速检测零日漏洞。对于开发人员团队:我希望他们会在不知道的情况下通过我们正在构建的自助服务 GUI(Vector)使用这两者,并且偶尔可能会通过 ssh 连接到一个实例并运行一个固定工具或临时 bpftrace one-liner。今年我还出版了一本涵盖 bpftrace 的书:BPF 性能工具:Linux 系统和应用程序可观察性,由 Addison Wesley 出版,其中包含许多新的 bpftrace 工具。感谢 Alastair Robertson 创建 bpftrace,感谢 bpftrace、BCC 和 BPF 社区在过去五年中所做的所有工作。你可以在这里发表评论,但我不能保证你的评论会永远留在这里:我可能会在某个时候切换评论系统(例如,如果disqus添加广告)。由 Disqus 提供支持的评论