Linux 中出现了一项新技术,可以为系统管理员和开发人员提供大量用于性能分析和故障排除的新工具和仪表板。它被称为增强型 Berkeley 数据包过滤器(eBPF,或简称 BPF),尽管这些增强功能不是在 Berkeley 开发的,但它们不仅仅对数据包进行操作,而且它们所做的不仅仅是过滤。我将讨论一种在Fedora
和 Red Hat
系列 Linux
发行版上使用BPF
的方法,并在 Fedora 26
上进行演示。
BPF 可以在内核中运行用户定义的沙盒程序,以立即添加新的自定义功能。这就像按需为Linux
添加超能力。您可以使用它的示例包括:
TCP
事件、用户级事件等的程序化低开销检测。DDOS
弹性,或在内核中重定向数据包以提高性能。24x7
自定义监控和可疑内核和用户空间事件的日志记录。BPF
程序必须通过内核验证程序以确保它们可以安全运行,这使其成为比编写自定义内核模块更安全的选择(在可能的情况下)。我怀疑大多数人不会自己编写BPF
程序,但会使用其他人的程序。我在 GitHub 上作为BPF Compiler Collection (bcc)项目的开源发布了很多。bcc
为BPF
开发提供了不同的前端,包括Python 和 Lua
,并且是目前BPF
工具最活跃的项目。
为了理解bcc/BPF
工具以及它们的作用,我创建了下图并将其添加到bcc
项目中:
这些是您可以通过 SSH
(安全外壳)使用的命令行界面(CLI)
工具。现在很多分析,包括在我的雇主那里,都是使用 GUI
和仪表板进行的。SSH
是最后的手段。但是这些CLI
工具仍然是预览 BPF
功能的好方法,即使您最终打算仅在可用时通过GUI
使用它们。我已经开始向开源GUI
添加BPF
功能,但这是另一篇文章的主题。现在我想分享您今天可以使用的 CLI
工具。
(execsnoop)
从哪儿开始?观看新流程怎么样?它们会消耗系统资源,但它们的生命周期很短,不会出现在top
或其他工具中。可以使用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()**系统调用来工作,该系统调用通常用于在新进程中加载不同的程序代码。
(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)正在打开(或试图打开)的文件:返回的文件描述符(FD
列)对于/etc/magic.mgc
是-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
的打开。Opensnoop
的开销也应该低得多:BPF
跟踪已经过优化,当前版本的strace(1)
仍然使用较旧且较慢的ptrace(2)
接口。
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
中的内核函数来实现,并在它结束时撤消该检测。此密件抄送工具也有适用于其他文件系统的版本:ext4slower
、btrfsslower
、zfsslower
和nfsslower
。
这是一个有用的工具,也是BPF
跟踪的一个重要示例。文件系统性能的传统分析侧重于块 I/O 统计信息——您通常会看到由iostat(1)
工具打印并由许多性能监控GUI
绘制的信息。这些统计数据显示了磁盘的性能,但并不是真正的文件系统。通常您更关心文件系统的性能而不是磁盘,因为它是应用程序向其发出请求和等待的文件系统。文件系统的性能可能与磁盘的性能大不相同!文件系统可以完全从内存缓存中读取,也可以通过预读算法填充该缓存并用于回写缓存。xfsslower
显示文件系统性能——应用程序直接体验到的性能。这对于免除整个存储子系统的责任通常很有用;如果真的没有文件系统延迟,那么性能问题很可能出在其他地方。
尽管文件系统性能对于了解应用程序性能很重要,但研究磁盘性能也有其优点。当各种缓存技巧无法再隐藏其延迟时,糟糕的磁盘性能最终会影响应用程序。磁盘性能也是容量规划的一个研究对象。
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 | |
这是另一个有用的工具和另一个有用的例子;它使用称为映射的BPF
功能,可用于实现高效的内核摘要统计。从内核层到用户层的数据传输仅仅是计数
列;用户级程序生成其余部分。
值得注意的是,许多这些工具都支持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
工具一样是设计使然,以帮助采用。
另一个有用的工具和示例是tcplife
,这次显示了 TCP
会话的生命周期和吞吐量统计信息:
# /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)
。
前面的每个示例都涉及内核跟踪,因此我至少需要一个用户级跟踪示例。这是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
的多次查找,遗憾的是这个主机并不存在,但我们仍然可以检查第一次和后续查找的延迟。(第二次查找后是否有一点负缓存?)
好吧,再举一个例子。跟踪工具由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
为“根”用户(我已登录)调用了pam_start()
。USAGE
消息(“trace -h”)
中有更多示例,此外,所有这些工具在 bcc
存储库中都有手册页和示例文件;例如,trace_example.txt
和trace.8
。
bcc
安装 bcc
的最佳方法是按照bcc INSTALL.md
中的说明从 iovisor
存储库中安装。IO Visor
是包含 bcc 的 Linux 基金会项目。这些工具使用的BPF
增强功能已添加到4.x
系列 Linux
内核中,最高可达 4.9
。这意味着具有4.8
内核的 Fedora 25
可以运行这些工具中的大部分;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
,它有以下错误:
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
性能分析超级功能的快速浏览。我向BPF
演示了流行的bcc
前端,并包含了 Fedora
的安装说明。bcc
带有60
多个用于性能分析的新工具,它们将帮助您充分利用Linux
系统。也许您会直接通过SSH
使用这些工具,或者一旦它们支持BPF
,您可能会通过监视GUI
使用相同的功能。
此外,bcc
并不是唯一正在开发的前端。有ply
和bpftrace
,旨在提供用于快速编写自定义工具的高级语言。此外,SystemTap
刚刚发布了3.2 版,其中包括一个早期的实验性eBPF
后端。如果继续开发它,它将提供一个生产安全和高效的引擎,用于运行多年来开发的许多SystemTap
脚本和tapsets
(库)。(将 SystemTap
与 eBPF
结合使用将是另一篇文章的好主题。)
如果您需要开发自定义工具,您也可以使用 bcc
,尽管该语言目前比 SystemTap
、ply
或 bpftrace
冗长得多。我的密件抄送工具可以用作代码示例,另外我还贡献了一个使用Python
开发密件抄送工具的教程。](https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md)我建议首先学习 bcc 多功能工具,因为在需要编写新工具之前,您可能会从中学到很多东西。您可以从 bcc 存储库中的示例文件中研究多功能工具:funccount、funclatency、funcslower、stackcount、trace和argdist。
联系客服