从入门到精通 eBPF 追踪

Jan 15, 2022 17:30 · 1886 words · 4 minute read eBPF Linux Performance

eBPF 全称是 extended Berkeley Packet Filter(扩展的伯克利包过滤器),可用于很多方向:网络性能、防火墙、安全、追踪和设备驱动。其中一些在网络上就能查到大量文档,比如追踪技术。追踪这个术语指的是性能分析;而追踪器是可观察性工具,用于生产相关事件的信息。我们经常使用的 tcpdump 和 strace 就是典型的追踪器。

这篇博客我将介绍学习 eBPF 追踪,面向初级、中级、高级用户。先抛结论:

  • 初级:使用 bcc 工具
  • 中级:使用并开发 bpftrace 工具
  • 高级:开发 bcc 工具

初级

1. 什么是 eBPF、bcc、bpftrace 和 iovisor

eBPF 是 Linux 内核的一部分。eBPF 之于 Linux 相当于 JavaScript 对 HTML 的作用。JavaScript 让你定义小程序,监听鼠标点击这样的事件,运行在浏览器的安全虚拟机中,代替全静态的 HTML 网页。有了 eBPF,你现在可以编写小程序,在磁盘 I/O 等事件发生时呼起,在内核的安全虚拟机中运行。实际上 eBPF 更像是运行 JavaScript 的 v8 虚拟机,而非 JavaScript 本身。

直接用 eBPF 编程难的一比,和用 v8 字节码编码没啥两样。没人直接用 v8 编码——大家用 JavaScript,甚至基于 JavaScript 上层的框架(jQuery、Angular、React等)。eBPF 也如是,最好通过框架对其编码。追踪方面主流的是 bccbpftrace 这两个项目,但并不在内核的代码仓库中,而是由 github 上一个名为 iovisor 的 Linux 项目托管。

2. eBPF 追踪案例

tcplife 这款基于 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 并不能实现所有功能——那得使用老的内核技术,但如果这么搞,出于性能和安全考虑,我们不能在生产环境中运行这样的工具。eBPF 所做的是让这个工具变得实用:既安全又高效:它不像旧技术那样追踪每一个数据包,这样会导致过多的性能开销;相反地,只追踪 TCP 会话事件,而这些事件的频率要低得多。这个工具的开销非常低,我们甚至可以在生产环境全天候(7 x 24)运行。

3. 如何使用

初学者直接尝试 bcc 软件包中的工具。查看 bcc 安装文档,每种 Linux 操作系统发行版的安装方式都不同。Ubuntu 呢只需要执行:

# sudo apt-get update

# 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 在内的很多公司都会在所有服务器上默认安装好 bcc 工具包。

4. 初学者教程

Brendan Gregg 写的 bcc Tutorial,非常适合 eBPF 追踪技术的初学者。

初来乍到你无需编写 eBPF 代码,bcc 有 70 多个现成的工具拿来就用。

bcc_tracing_tools

全都有完备的文档,示例文件(bcc/tools 的 *_example.txt)还带了不少截屏,比如 biolatency_example.txt。随着时间的推移,越来越多的生产案例会被添加到文档中。

中级

这时你应该已经尝试了这些工具,要是对定制和编写自己的工具感兴趣,最好的办法是切换到 bpftrace,它有一个更易于学习的高级语言。但缺点是不像 bcc 那样可以定制,所以你可能最终会碰到一些限制,想换回 bcc。

每种 Linux 操作系统发行版的安装方式有所不同,查看 bpftrace 安装文档

1. bpftrace 教程

Brendan Gregg 写的 bpftrace One-Liners Tutorial,提供了 12 讲一点一点教你怎么用 bpftrace:

# bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("%d %s\n", pid, str(args->filename)); }'
Attaching 1 probe...
181 /proc/cpuinfo
181 /proc/stat
1461 /proc/net/dev
1461 /proc/net/if_inet6
^C

使用 open 系统调用的追踪点来追踪 PID 和打开的路径。

2. bpftrace 参考指南

如果想要深入了解 bpftrace,Brendan Gregg 写了一份参考指南 bpftrace Reference Guide,有相关语法、探针和内置程序的例子。编排后的目录链接至对应的内容,我觉得可以当成工具书来使用。

3. bpftrace 案例

在 bpftrace 的仓库中有 20 多种工具 https://github.com/iovisor/bpftrace/tree/master/tools

举个栗子:

# 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 一样,这些工具都有说明书和示例文件。

高级

1. 学习 bcc 开发

这方面请先阅读以下两份文档:

bcc/tools/ 路径下有不少 Python 代码示例。bcc 工具由两部分组成:用 C 编写的内核 BPF 代码和用 Python(或者 lua 和 C++)编写的用户空间工具。开发 bcc 工具有点难,因为要深入内核或应用程序内部。

2. 为社区贡献

在这提交问题:

在 llvm IR 中编码是极其困难的,你想接受挑战也不是不可以。先看看这份指南 bpftrace Internals Development Guide

还有内核中的 eBPF 引擎,浏览 bcc 和 bpftrace 的 issue 时能看到有些增强功能的请求。

重要的事再说一遍

  • 初级:使用 bcc 工具
  • 中级:使用并开发 bpftrace 工具
  • 高级:开发 bcc 工具

Good luck!


logo