一项新技术已经出现在 Linux 中,它可以为系统管理员和开发人员提供大量用于性能分析和故障排除的新工具和仪表板。它被称为增强型 Berkeley Packet Filter(eBPF,或简称 BPF),尽管这些增强功能不是在伯克利开发的,但它们的操作远不止数据包,而且它们的功能也远不止过滤。我将讨论在 Fedora 和 Red Hat 系列 Linux 发行版上使用 BPF 的一种方法,并在 Fedora 26 上进行演示。
BPF 可以在内核中运行用户定义的沙盒程序,以立即添加新的自定义功能。这就像按需为 Linux 添加超能力。您可以将其用于以下示例:
- 高级性能跟踪工具:对文件系统操作、TCP 事件、用户级事件等进行程序化的低开销检测。
- 网络性能:尽早丢弃数据包以提高 DDOS 弹性,或在内核中重定向数据包以提高性能
- 安全监控:24x7 自定义监控和记录可疑的内核和用户空间事件
BPF 程序必须通过内核内验证器,以确保它们可以安全运行,这使其成为一种更安全的选择(如果可能),而不是编写自定义内核模块。我怀疑大多数人不会自己编写 BPF 程序,而是会使用别人的程序。我已经在 GitHub 上以开源形式发布了许多程序,位于 BPF Compiler Collection (bcc) 项目中。bcc 为 BPF 开发提供了不同的前端,包括 Python 和 Lua,并且目前是 BPF 工具领域最活跃的项目。
7 个有用的新 bcc/BPF 工具
为了理解 bcc/BPF 工具及其检测的内容,我创建了以下图表并将其添加到 bcc 项目中

opensource.com
这些是可以通过 SSH(安全外壳)使用的命令行界面 (CLI) 工具。现在的大部分分析(包括我的雇主)都是使用 GUI 和仪表板进行的。SSH 是最后的手段。但是,即使您最终只打算在 GUI 可用时通过 GUI 使用它们,这些 CLI 工具仍然是预览 BPF 功能的好方法。我已经开始向开源 GUI 添加 BPF 功能,但这将是另一篇文章的主题。现在我想分享 CLI 工具,您可以立即使用它们。
1. execsnoop
从哪里开始呢?如何监视新进程。这些进程可能会消耗系统资源,但生命周期太短,以至于不会显示在 top(1) 或其他工具中。可以使用 execsnoop 对它们进行检测(或者,使用行业术语,它们可以被跟踪)。在跟踪时,我将在另一个窗口中通过 SSH 登录
# /usr/share/bcc/tools/execsnoop
PCOMM PID PPID RET ARGS
sshd 12234 727 0 /usr/sbin/sshd -D -R
unix_chkpwd 12236 12234 0 /usr/sbin/unix_chkpwd root nonull
unix_chkpwd 12237 12234 0 /usr/sbin/unix_chkpwd root chkexpiry
bash 12239 12238 0 /bin/bash
id 12241 12240 0 /usr/bin/id -un
hostname 12243 12242 0 /usr/bin/hostname
pkg-config 12245 12244 0 /usr/bin/pkg-config --variable=completionsdir bash-completion
grepconf.sh 12246 12239 0 /usr/libexec/grepconf.sh -c
grep 12247 12246 0 /usr/bin/grep -qsi ^COLOR.*none /etc/GREP_COLORS
tty 12249 12248 0 /usr/bin/tty -s
tput 12250 12248 0 /usr/bin/tput colors
dircolors 12252 12251 0 /usr/bin/dircolors --sh /etc/DIR_COLORS
grep 12253 12239 0 /usr/bin/grep -qi ^COLOR.*none /etc/DIR_COLORS
grepconf.sh 12254 12239 0 /usr/libexec/grepconf.sh -c
grep 12255 12254 0 /usr/bin/grep -qsi ^COLOR.*none /etc/GREP_COLORS
grepconf.sh 12256 12239 0 /usr/libexec/grepconf.sh -c
grep 12257 12256 0 /usr/bin/grep -qsi ^COLOR.*none /etc/GREP_COLORS
哇。这都是什么?什么是 grepconf.sh?什么是 /etc/GREP_COLORS?grep 真的在读取它自己的配置文件...通过运行 grep?这怎么可能?
欢迎来到系统跟踪的乐趣。您可以了解很多关于系统真正如何工作(或不工作,视情况而定)的信息,并在此过程中发现一些简单的优化。execsnoop 通过跟踪 exec() 系统调用来工作,该系统调用通常用于在新进程中加载不同的程序代码。
2. opensnoop
从上面继续,那么,grepconf.sh 很可能是一个 shell 脚本,对吗?我将运行 file(1) 进行检查,并使用 opensnoop bcc 工具来查看正在打开什么文件
# /usr/share/bcc/tools/opensnoop
PID COMM FD ERR PATH
12420 file 3 0 /etc/ld.so.cache
12420 file 3 0 /lib64/libmagic.so.1
12420 file 3 0 /lib64/libz.so.1
12420 file 3 0 /lib64/libc.so.6
12420 file 3 0 /usr/lib/locale/locale-archive
12420 file -1 2 /etc/magic.mgc
12420 file 3 0 /etc/magic
12420 file 3 0 /usr/share/misc/magic.mgc
12420 file 3 0 /usr/lib64/gconv/gconv-modules.cache
12420 file 3 0 /usr/libexec/grepconf.sh
1 systemd 16 0 /proc/565/cgroup
1 systemd 16 0 /proc/536/cgroup
像 execsnoop 和 opensnoop 这样的工具每个事件打印一行。这显示了 file(1) 正在打开(或尝试打开)的文件:对于 /etc/magic.mgc,返回的文件描述符(“FD”列)是 -1,并且 “ERR”列指示它是“找不到文件”。我不知道那个文件,也不知道 file(1) 正在读取的 /usr/share/misc/magic.mgc。我不应该感到惊讶,但是 file(1) 在识别文件类型方面没有问题
# file /usr/share/misc/magic.mgc /etc/magic
/usr/share/misc/magic.mgc: magic binary file for file(1) cmd (version 14) (little endian)
/etc/magic: magic text file for file(1) cmd, ASCII text
opensnoop 通过跟踪 open() 系统调用来工作。为什么不直接使用 strace -feopen file ...?在这种情况下可以工作。但是,opensnoop 的几个优点是它可以系统范围内工作,并且可以跨所有进程跟踪 open() 调用。请注意,上面的输出包括来自 systemd 的 opens。Opensnoop 也应该具有低得多的开销:BPF 跟踪已经过优化,并且当前版本的 strace(1) 仍然使用较旧且较慢的 ptrace(2) 接口。
3. xfsslower
bcc/BPF 可以分析的远不止系统调用。xfsslower 工具跟踪延迟大于 1 毫秒(参数)的常见 XFS 文件系统操作
# /usr/share/bcc/tools/xfsslower 1
Tracing XFS operations slower than 1 ms
TIME COMM PID T BYTES OFF_KB LAT(ms) FILENAME
14:17:34 systemd-journa 530 S 0 0 1.69 system.journal
14:17:35 auditd 651 S 0 0 2.43 audit.log
14:17:42 cksum 4167 R 52976 0 1.04 at
14:17:45 cksum 4168 R 53264 0 1.62 [
14:17:45 cksum 4168 R 65536 0 1.01 certutil
14:17:45 cksum 4168 R 65536 0 1.01 dir
14:17:45 cksum 4168 R 65536 0 1.17 dirmngr-client
14:17:46 cksum 4168 R 65536 0 1.06 grub2-file
14:17:46 cksum 4168 R 65536 128 1.01 grub2-fstest
[...]
在上面的输出中,我捕获了许多延迟超过 1 毫秒的 cksum(1) 读取(“T”表示类型 == “R”)。这通过在 xfsslower 工具运行时动态检测 XFS 中的内核函数来工作,并在工具结束时撤消该检测。此 bcc 工具也有适用于其他文件系统的版本:ext4slower、btrfsslower、zfsslower 和 nfsslower。
这是一个有用的工具,也是 BPF 跟踪的重要示例。传统的文件系统性能分析侧重于块 I/O 统计信息——您通常在 iostat(1) 工具打印的内容和许多性能监控 GUI 绘制的图中看到这些信息。这些统计信息显示了磁盘的性能,但实际上不是文件系统的性能。通常,您更关心文件系统的性能而不是磁盘的性能,因为应用程序向文件系统发出请求并等待响应。文件系统的性能可能与磁盘的性能大相径庭!文件系统可能会完全从内存缓存中提供读取服务,并通过预读算法和用于写回缓存来填充该缓存。xfsslower 显示文件系统性能——应用程序直接体验到的性能。这通常有助于证明整个存储子系统是清白的;如果确实没有文件系统延迟,那么性能问题很可能出现在其他地方。
4. biolatency
虽然文件系统性能对于理解应用程序性能很重要,但研究磁盘性能也很有价值。当各种缓存技巧无法再隐藏其延迟时,磁盘性能不佳最终会影响应用程序。磁盘性能也是容量规划的研究目标。
iostat(1) 工具显示平均磁盘 I/O 延迟,但平均值可能会产生误导。以直方图的形式研究 I/O 延迟的分布可能很有用,这可以使用 biolatency 完成
# /usr/share/bcc/tools/biolatency
Tracing block device I/O... Hit Ctrl-C to end.
^C
usecs : count distribution
0 -> 1 : 0 | |
2 -> 3 : 0 | |
4 -> 7 : 0 | |
8 -> 15 : 0 | |
16 -> 31 : 0 | |
32 -> 63 : 1 | |
64 -> 127 : 63 |**** |
128 -> 255 : 121 |********* |
256 -> 511 : 483 |************************************ |
512 -> 1023 : 532 |****************************************|
1024 -> 2047 : 117 |******** |
2048 -> 4095 : 8 | |
这是另一个有用的工具和另一个有用的示例;它使用了一个名为 maps 的 BPF 功能,该功能可用于实现高效的内核内摘要统计信息。从内核级别到用户级别的数据传输仅仅是“count”列;用户级程序生成其余部分。
值得注意的是,这些工具中的许多工具都支持 CLI 选项和参数,如其 USAGE 消息所示
# /usr/share/bcc/tools/biolatency -h
usage: biolatency [-h] [-T] [-Q] [-m] [-D] [interval] [count]
Summarize block device I/O latency as a histogram
positional arguments:
interval output interval, in seconds
count number of outputs
optional arguments:
-h, --help show this help message and exit
-T, --timestamp include timestamp on output
-Q, --queued include OS queued time in I/O time
-m, --milliseconds millisecond histogram
-D, --disks print a histogram per disk device
examples:
./biolatency # summarize block I/O latency as a histogram
./biolatency 1 10 # print 1 second summaries, 10 times
./biolatency -mT 1 # 1s summaries, milliseconds, and timestamps
./biolatency -Q # include OS queued time in I/O time
./biolatency -D # show each disk device separately
它们像其他 Unix 工具一样运行是经过设计的,目的是为了帮助采用。
5. tcplife
另一个有用的工具和示例,这次显示 TCP 会话的生命周期和吞吐量统计信息的是 tcplife
# /usr/share/bcc/tools/tcplife
PID COMM LADDR LPORT RADDR RPORT TX_KB RX_KB MS
12759 sshd 192.168.56.101 22 192.168.56.1 60639 2 3 1863.82
12783 sshd 192.168.56.101 22 192.168.56.1 60640 3 3 9174.53
12844 wget 10.0.2.15 34250 54.204.39.132 443 11 1870 5712.26
12851 curl 10.0.2.15 34252 54.204.39.132 443 0 74 505.90
在您说:“我不能仅仅为了这个目的抓取 tcpdump(8) 输出吗?”之前,请注意,运行 tcpdump(8) 或任何数据包嗅探器可能会在高数据包速率系统上造成明显的开销,即使 tcpdump(8) 的用户级和内核级机制多年来已经过优化(它可能会更糟)。tcplife 不会检测每个数据包;它仅监视 TCP 会话状态更改以提高效率,并从中计算会话的持续时间。它还使用已经跟踪吞吐量的内核计数器,以及进程和命令信息(“PID”和“COMM”列),这些信息对于像 tcpdump(8) 这样的在线嗅探工具不可用。
6. gethostlatency
之前的每个示例都涉及内核跟踪,所以我至少需要一个用户级跟踪示例。这是 gethostlatency,它检测 gethostbyname(3) 和相关的用于名称解析的库调用
# /usr/share/bcc/tools/gethostlatency
TIME PID COMM LATms HOST
06:43:33 12903 curl 188.98 opensource.com
06:43:36 12905 curl 8.45 opensource.com
06:43:40 12907 curl 6.55 opensource.com
06:43:44 12911 curl 9.67 opensource.com
06:45:02 12948 curl 19.66 opensource.cats
06:45:06 12950 curl 18.37 opensource.cats
06:45:07 12952 curl 13.64 opensource.cats
06:45:19 13139 curl 13.10 opensource.cats
是的,总是 DNS,因此拥有一个系统范围的 DNS 请求监视工具可能很方便(这仅在应用程序使用标准系统库时才有效)。看看我是如何跟踪对“opensource.com”的多次查找的?第一次花费了 188.98 毫秒,然后速度快得多,不到 10 毫秒,毫无疑问是缓存了。它还跟踪了对“opensource.cats”的多次查找,这是一个可悲地不存在的主机,但我们仍然可以检查第一次和后续查找的延迟。(第二次查找后是否有一点负缓存?)
7. trace
好的,再举一个例子。trace 工具由 Sasha Goldshtein 贡献,并提供了一些基本的 printf(1) 功能以及自定义探针。例如
# /usr/share/bcc/tools/trace 'pam:pam_start "%s: %s", arg1, arg2'
PID TID COMM FUNC -
13266 13266 sshd pam_start sshd: root
在这里,我正在跟踪 libpam 及其 pam_start(3) 函数,并将它的两个参数都打印为字符串。Libpam 用于可插拔身份验证模块系统,输出显示 sshd 为“root”用户调用了 pam_start()(我已登录)。USAGE 消息(“trace -h”)中有更多示例,此外,所有这些工具在 bcc 存储库中都有手册页和示例文件;例如,trace_example.txt 和 trace.8。
通过软件包安装 bcc
安装 bcc 的最佳方法是从 iovisor 存储库安装,按照 bcc INSTALL.md 中的说明进行操作。IO Visor 是包含 bcc 的 Linux 基金会项目。这些工具使用的 BPF 增强功能是在 4.x 系列 Linux 内核(最高到 4.9)中添加的。这意味着 Fedora 25(使用 4.8 内核)可以运行大多数这些工具;而 Fedora 26(使用 4.11 内核)可以运行所有这些工具(至少目前是这样)。
如果您使用的是 Fedora 25(或 Fedora 26,并且这篇文章是在几个月前发布的——来自遥远过去的问候!),那么这种软件包方法应该可以正常工作。如果您使用的是 Fedora 26,请跳到 通过源代码安装 部分,该部分避免了 已知 且 已修复 的错误。该错误修复程序目前尚未进入 Fedora 26 软件包依赖项。我正在使用的系统是
# uname -a
Linux localhost.localdomain 4.11.8-300.fc26.x86_64 #1 SMP Thu Jun 29 20:09:48 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# cat /etc/fedora-release
Fedora release 26 (Twenty Six)
以下是我遵循的安装步骤,但请参阅 INSTALL.md 以获取更新的版本
# echo -e '[iovisor]\nbaseurl=https://repo.iovisor.org/yum/nightly/f25/$basearch\nenabled=1\ngpgcheck=0' | sudo tee /etc/yum.repos.d/iovisor.repo
# dnf install bcc-tools
[...]
Total download size: 37 M
Installed size: 143 M
Is this ok [y/N]: y
安装后,您应该在 /usr/share 中看到新工具
# ls /usr/share/bcc/tools/
argdist dcsnoop killsnoop softirqs trace
bashreadline dcstat llcstat solisten ttysnoop
[...]
让我们尝试运行其中一个
# /usr/share/bcc/tools/opensnoop
chdir(/lib/modules/4.11.8-300.fc26.x86_64/build): No such file or directory
Traceback (most recent call last):
File "/usr/share/bcc/tools/opensnoop", line 126, in <module>
b = BPF(text=bpf_text)
File "/usr/lib/python3.6/site-packages/bcc/__init__.py", line 284, in __init__
raise Exception("Failed to compile BPF module %s" % src_file)
Exception: Failed to compile BPF module
它未能运行,并抱怨缺少 /lib/modules/4.11.8-300.fc26.x86_64/build。如果您也遇到这种情况,那只是因为系统缺少内核头文件。如果您查看该文件指向的内容(它是一个符号链接),然后使用“dnf whatprovides”搜索它,它会告诉您接下来需要安装的软件包。对于此系统,它是
# dnf install kernel-devel-4.11.8-300.fc26.x86_64
[...]
Total download size: 20 M
Installed size: 63 M
Is this ok [y/N]: y
[...]
现在
# /usr/share/bcc/tools/opensnoop
PID COMM FD ERR PATH
11792 ls 3 0 /etc/ld.so.cache
11792 ls 3 0 /lib64/libselinux.so.1
11792 ls 3 0 /lib64/libcap.so.2
11792 ls 3 0 /lib64/libc.so.6
[...]
它可以工作了。这是从另一个窗口中的 ls 命令捕获的活动。请参阅前面的部分以获取其他有用的命令。
通过源代码安装
如果您需要从源代码安装,您还可以在 INSTALL.md 中找到文档和更新的说明。我在 Fedora 26 上执行了以下操作
sudo dnf install -y bison cmake ethtool flex git iperf libstdc++-static \
python-netaddr python-pip gcc gcc-c++ make zlib-devel \
elfutils-libelf-devel
sudo dnf install -y luajit luajit-devel # for Lua support
sudo dnf install -y \
http://pkgs.repoforge.org/netperf/netperf-2.6.0-1.el6.rf.x86_64.rpm
sudo pip install pyroute2
sudo dnf install -y clang clang-devel llvm llvm-devel llvm-static ncurses-devel
除 netperf 外,所有内容都为我安装了,netperf 出现以下错误
Curl error (28): Timeout was reached for http://pkgs.repoforge.org/netperf/netperf-2.6.0-1.el6.rf.x86_64.rpm [Connection timed out after 120002 milliseconds]
我们可以忽略此错误,因为 netperf 是可选的——它仅用于测试——并且 bcc 将在没有它的情况下编译。
以下是剩余的 bcc 编译和安装步骤
git clone https://github.com/iovisor/bcc.git
mkdir bcc/build; cd bcc/build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make
sudo make install
此时,命令应该可以工作了
# /usr/share/bcc/tools/opensnoop
PID COMM FD ERR PATH
4131 date 3 0 /etc/ld.so.cache
4131 date 3 0 /lib64/libc.so.6
4131 date 3 0 /usr/lib/locale/locale-archive
4131 date 3 0 /etc/localtime
[...]
结束语和其他前端
这是对您可以在 Fedora 和 Red Hat 系列操作系统上使用的新 BPF 性能分析超能力的快速浏览。我演示了流行的 bcc BPF 前端,并包含了 Fedora 的安装说明。bcc 附带 60 多个用于性能分析的新工具,这将帮助您充分利用 Linux 系统。也许您将通过 SSH 直接使用这些工具,或者也许您将在监控 GUI 支持 BPF 后通过它们使用相同的功能。
此外,bcc 不是唯一正在开发的前端。还有 ply 和 bpftrace,它们旨在提供更高级别的语言来快速编写自定义工具。此外,SystemTap 刚刚发布了 3.2 版本,其中包括早期、实验性的 eBPF 后端。如果继续开发,它将为运行多年来开发的许多 SystemTap 脚本和 tapset(库)提供生产安全且高效的引擎。(将 SystemTap 与 eBPF 结合使用将是另一篇文章的好主题。)
如果您需要开发自定义工具,您也可以使用 bcc 来完成,尽管该语言目前比 SystemTap、ply 或 bpftrace 冗长得多。我的 bcc 工具可以用作代码示例,此外,我还在 Python 中贡献了一个用于开发 bcc 工具的 教程。我建议首先学习 bcc 多工具,因为在需要编写新工具之前,您可能会从它们那里获得很多好处。您可以从 bcc 存储库中的示例文件中研究多工具:funccount、funclatency、funcslower、stackcount、trace 和 argdist。
感谢 Opensource.com 的编辑。
4 条评论