学习 eBPF 跟踪:教程和示例

在 Linux Plumber 的会议上,至少有 24 场关于 eBPF 的演讲。它已迅速成为一项非常宝贵的技术,而且成为一项抢手的技能。也许你想要一个新年的决心:学习 eBPF!

eBPF 应该代表一些有意义的东西,比如虚拟内核指令集(VKIS),但由于它的起源,它是伯克利包过滤器的扩展。它可用于许多方面:网络性能、防火墙、安全性、跟踪和设备驱动程序。其中一些在线上有大量免费文档,例如用于跟踪,而另一些则还没有。跟踪一词是指可以生成每个事件信息的性能分析和可观察性工具。您可能已经使用过跟踪器:tcpdump和strace是专门的跟踪器。

在这篇文章中,我将介绍学习 eBPF 以进行跟踪,分为初学者、中级和高级用户的内容。总之:

  • 初学者:运行bcc工具
  • 中级:开发bpftrace工具
  • 进阶:开发bcc工具,为 bcc & bpftrace 做贡献

初学者

1、什么是eBPF、bcc、bpftrace、iovisor?

eBPF 对 Linux 的作用就像 JavaScript 对 HTML 的作用一样。(有点。)因此,JavaScript 不是静态的 HTML 网站,而是允许您定义在鼠标点击等事件上运行的小程序,这些小程序在浏览器中的安全虚拟机中运行。使用 eBPF,您现在可以编写运行在磁盘 I/O 等事件上的小程序,而不是固定的内核,这些事件在内核中的安全虚拟机中运行。实际上,eBPF 更像是运行 JavaScript 的 v8 虚拟机,而不是 JavaScript 本身。eBPF 是 Linux 内核的一部分。

直接在 eBPF 中编程非常困难,就像在 v8 字节码中编码一样。但是没有人在 v8 中编写代码:他们使用 JavaScript 编写代码,或者通常是 JavaScript 之上的框架(jQuery、Angular、React 等)。eBPF 也是如此。人们将通过框架使用它并在其中编写代码。对于跟踪,主要是**bcc** 和**bpftrace** 。这些并不存在于内核代码库中,它们存在于 github 上名为iovisor 的 Linux Foundation 项目中。

2. eBPF 追踪的一个例子是什么?

这个基于 eBPF 的工具显示已完成的 TCP 会话,以及它们的进程 ID (PID) 和命令名称 (COMM)、发送和接收的字节数 (TX_KB、RX_KB) 以及以毫秒为单位的持续时间 (MS):

# tcplife
PID   COMM       LADDR           LPORT RADDR           RPORT TX_KB RX_KB MS
22597 recordProg 127.0.0.1       46644 127.0.0.1       28527     0     0 0.23
3277  redis-serv 127.0.0.1       28527 127.0.0.1       46644     0     0 0.28
22598 curl       100.66.3.172    61620 52.205.89.26    80        0     1 91.79
22604 curl       100.66.3.172    44400 52.204.43.121   80        0     1 121.38
22624 recordProg 127.0.0.1       46648 127.0.0.1       28527     0     0 0.22
3277  redis-serv 127.0.0.1       28527 127.0.0.1       46648     0     0 0.27
22647 recordProg 127.0.0.1       46650 127.0.0.1       28527     0     0 0.21
3277  redis-serv 127.0.0.1       28527 127.0.0.1       46650     0     0 0.26
[...]

eBPF没有 让这成为可能——我可以重写 tcplife 以使用旧的内核技术。但如果我这样做了,由于性能开销、安全问题或两者兼而有之,我们永远不会在生产中运行这样的工具。eBPF 所做的就是让这个工具变得实用 :它既高效又安全。例如,它不像旧技术那样跟踪每个数据包,这会增加太多的性能开销。相反,它只跟踪不太频繁的 TCP 会话事件。这使得开销如此之低,我们可以在生产环境中运行这个工具,24x7。

3. 如何使用?

对于初学者,请尝试 bcc 中的工具。请参阅适用于您的操作系统的bcc安装说明。在 Ubuntu 上,它可能是这样的:

# sudo apt-get install bpfcc-tools
# sudo /usr/share/bcc/tools/opensnoop
PID    COMM               FD ERR PATH
25548  gnome-shell        33   0 /proc/self/stat
10190  opensnoop          -1   2 /usr/lib/python2.7/encodings/ascii.x86_64-linux-gnu.so
10190  opensnoop          -1   2 /usr/lib/python2.7/encodings/ascii.so
10190  opensnoop          -1   2 /usr/lib/python2.7/encodings/asciimodule.so
10190  opensnoop          18   0 /usr/lib/python2.7/encodings/ascii.py
10190  opensnoop          19   0 /usr/lib/python2.7/encodings/ascii.pyc
25548  gnome-shell        33   0 /proc/self/stat
29588  device poll         4   0 /dev/bus/usb
^C

在那里,我通过运行 opensnoop 来测试这些工具是否有效。如果你走到这一步,你已经使用了 eBPF!

默认情况下,包括 Netflix 和 Facebook 在内的公司在所有服务器上都安装了密件抄送,也许您也想这样做。

4. 有初学者教程吗?

是的,我创建了一个密件抄送教程,这是初学者进行 eBPF 跟踪的一个很好的起点:

作为初学者,您不需要编写任何 eBPF 代码。bcc 附带 70 多种工具,您可以立即使用。本教程将引导您完成其中的 11 个:execsnoop、opensnoop、ext4slower(或 btrfs*、xfs*、zfs*)、biolatency、biosnoop、cachestat、tcpconnect、tcpaccept、tcpretrans、runqlat 和 profile。

一旦你尝试了这些,你只需要知道还有更多:

这些也完全记录在手册页和示例文件中。示例文件(bcc/tools 中的 *_example.txt)显示带有解释的屏幕截图:例如biolatency_example.txt。我编写了许多示例文件(以及手册页和工具),它们就像您可以在 bcc 存储库中找到的额外 50 篇博客文章。

缺少的是生产示例。当 eBPF 很新时,我编写了所有这些文档,它只在我们的测试实例上可用,所以大多数示例都是合成的。随着时间的推移,我们将添加真实世界的示例,这是初学者可以提供帮助的领域:如果您使用工具解决问题,请考虑发布帖子以共享屏幕截图,或将其添加到示例文件中。

中间的

此时,您应该运行 bcc 并尝试了这些工具,并且您对自定义它们和编写自己的工具感兴趣。最好的方法是切换到 bpftrace,它具有更容易学习的高级语言 。缺点是它不像密件抄送那样可定制,因此您最终可能会遇到限制并想要切换回密件抄送。

请参阅bpftrace 安装说明。这是一个较新的项目,因此在撰写本文时它并未随处打包。将来,它应该只是apt-get install bpftrace或等效的。

1. bpftrace 教程

我开发了一个教程,通过一系列单行教程教授 bpftrace:

Attaching 1 probe...
181 /proc/cpuinfo
181 /proc/stat
1461 /proc/net/dev
1461 /proc/net/if_inet6
^C

那是使用打开的系统调用跟踪点来跟踪打开的 PID 和路径。

2. bpftrace 参考指南

有关 bpftrace 的更多信息,我创建了参考指南,其中包含语法、探针和内置函数的示例:

故意简洁:我尽可能将主题标题、摘要和屏幕截图全部放在一个屏幕上。如果您查找某些内容并且需要多次向下翻页,我认为它太长了。

3. bpftrace 示例

bpftrace 存储库中有 20 多个工具,您可以浏览这些工具作为示例:

例如:

# cat tools/biolatency.bt
[...]
BEGIN
{
    printf("Tracing block device I/O... Hit Ctrl-C to end.\n");
}

kprobe:blk_account_io_start
{
    @start[arg0] = nsecs;
}

kprobe:blk_account_io_completion
/@start[arg0]/

{
    @usecs = hist((nsecs - @start[arg0]) / 1000);
    delete(@start[arg0]);
}

与 bcc 一样,这些工具也有手册页和示例文件。例如,biolatency_example.txt

高级的

1.学习bcc开发

我创建了两个文档来帮助这里:

在 bcc/tools/*.py 下也有很多例子。bcc 工具分为两部分:用于内核的 BPF 代码,用 C 编写,以及用 Python(或 lua,或 C++)编写的用户空间工具。开发 bcc 工具有些先进,可能涉及一些坚韧不拔的内核或应用程序内部。

2. 贡献

帮助表示赞赏:

对于 bpftrace,我创建了bpftrace 内部开发指南。当你在 llvm IR 中编码时会变得很困难,但如果你准备好迎接挑战…

还有内核 eBPF(又名 BPF)引擎:如果您浏览 bcc 和 bpftrace 问题,您会在那里看到一些增强请求。例如,bpftrace 内核标签。还可以查看netdev邮件列表,了解最新的内核 BPF 开发,这些开发在合并到主线 Linux 之前被添加到 net-next。

除了编写代码之外,您还可以为测试、打包、博客文章和演讲做出贡献。