暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用Pixie运行分布式bpftrace

CNCF 2021-11-04
2243


标准票和免费票|马上扫码注册!




作者:Arnold van Wijnbergen

我最近听过 Pixie:一个给基于微服务应用程序的开源调试平台。Pixie 是使用 Linux eBPF 技术构建的[1],该技术承诺提供自动监控。除了它的原生跟踪的协议之外[2],Pixie 还有一个特性,使我们能够在集群上执行类似 bpftrace 的脚本,这非常棒。在看到 Pixie 于 2021 年 4 月发布后,我决定研究 Pixie 及其 bpftrace 功能。

为了初步了解实际的实现,我从 Pixie 的参考视频[3]开始,其中转换了 bpftrace 的 tcp-retransmit.bt 到实际的 PxL 脚本。在那个 Youtube 视频中,一切似乎都解释得很好,所以我继续我的旅程。

在这篇文章中,我将向你展示如何使用 Pixie 部署 bpftrace 代码,并分享我为 Pixie 贡献的转换后的 bpftrace 工具脚本。

bpftrace 背景

如果你不熟悉 bpftrace,也没有问题。bpftrace 是一个为 eBPF 提供高级跟踪语言的工具。在后台,它使用 BCC Toolkit(IO Visor 项目[4])和 LLVM 将所有脚本编译为 bpf 字节码。它支持内核探测(Kprobes)、用户级探测(Uprobes)和跟踪点。bpftrace 本身深受 awk、sed 等工具以及 DTrace 和 SystemTap 等跟踪器的启发,因此我们可以创建非常棒的一行程序。

这使得该工具非常强大,但也有一个缺点,因为它只能在本地运行,不能提供在远程系统上分布式运行的功能,也没有一个中央 UI。

Pixie 可以帮我们把这些事搞定。Pixie 可以跨 Kubernetes 集群分发 eBPF 程序,并提供可以从 UI、CLI 或 API 轻松查询的表。

修改 sleepy_snoop 移植到 Pixie

让我们开发第一个 bpftrace PxL 脚本。对于本例,我们将使用一个著名的一行代码,我们将其称为 sleepy_snoop。让我们首先看看实际的代码本身。

kprobe:do_nanosleep { printf("PID %d sleeping\n", pid); }

复制

Pixie 需要做一些小的调整[5],使这些代码在 PxL 脚本中工作:

  • 首先,我们必须转义 printf 双引号。
  • 我们需要一个 printf 语句,其中包含字段名作为 Pixie 表的实际输出,因此我们必须调整 kprobe:do_nanosleep 块中的 printf 语句,以包含 pid 列名。
  • 此外,我们还将使用时间戳和进程名来丰富输出。我们可以在字段名 time_原生使用 nsecs。Pixie 可以识别该字段,并自动显示为人类可读的日期时间格式。为了记录进程名,我们使用内置的 comm 变量。

转换后的 eBPF 程序应该如下所示:

kprobe:do_nanosleep { printf(\"time_:%llu pid:%d comm:%s\", nsecs, pid, comm); }


复制

从 Pixie CLI 运行 sleepy_snoop

现在我们有了 eBPF 代码,可以创建实际的 PxL 脚本了。你可以在这里[6]找到这个脚本。

# Import Pixie's modules for creating traces & querying data
import pxtrace
import px

# Adapted from https://brendangregg.com

program = """
kprobe:do_nanosleep { printf(\"time_:%llu pid:%d comm:%s\", nsecs, pid, comm); }
"
""

# sleepy_snoop_func function to create a tracepoint
# and start the data collection.
def sleepy_snoop_func():
    table_name = 'sleepy_snoop_table'
    pxtrace.UpsertTracepoint('sleepy_snoop_tracer',
                             table_name,
                             program,
                             pxtrace.kprobe(),
                             "10m")
    df = px.DataFrame(table=table_name)

    return df

output = sleepy_snoop_func();

# display the tracepoint table data
px.display(output)

复制

这个脚本看起来与 PxL 脚本有些不同,后者只是查询已经收集的数据。简而言之,我们:

  • 导入 px 和 pxtrace 库。
  • 创建一个包含 BPF 代码的 program 变量。
  • 创建一个函数来执行跟踪点集合。在我们的例子中是 sleepy_snoop_func。
  • 定义要将结果放入的目标 Pixie 表,称为 sleepy_snoop_table。
  • 定义跟踪点来启动称为 sleepy_snoop_tracer 的 Kprobe。这包括 10m 的生存时间,它会在最后一次脚本执行 10 分钟后自动删除 eBPF 探测。
  • 从结果表中创建一个 DataFrame 对象并将其显示在 UI 中。

你可以使用 Pixie 的 CLI 运行该脚本:

px run -f sleepy_snoop.pxl

复制

有关如何使用 Pixie CLI 的更多帮助,请参阅教程[7]

下面是 CLI 输出的一个示例。注意,在某些情况下,你可能需要运行脚本两次。这是因为脚本在第一次运行时可能还没有收集到要显示的任何数据。

px run -f sleepy_snoop.pxl
Pixie CLI
Table ID: output
  TIME                                      PID    COMM
  2021-09-27 20:11:15.546971049 +0200 CEST  12123  pem
  2021-09-27 20:11:15.614823431 +0200 CEST  4261   k8s_metadata
  2021-09-27 20:11:15.615110023 +0200 CEST  4261   k8s_metadata
  2021-09-27 20:11:15.615132796 +0200 CEST  8077   metadata
  2021-09-27 20:11:15.615196553 +0200 CEST  4261   k8s_metadata
  2021-09-27 20:11:15.621200052 +0200 CEST  4261   k8s_metadata
  2021-09-27 20:11:15.621290646 +0200 CEST  4261   k8s_metadata
  2021-09-27 20:11:15.621375788 +0200 CEST  4261   k8s_metadata
  2021-09-27 20:11:15.546333885 +0200 CEST  6952   containerd-shim
  2021-09-27 20:11:15.546344427 +0200 CEST  1495   containerd
  2021-09-27 20:11:15.546366425 +0200 CEST  1495   containerd
  2021-09-27 20:11:15.546429576 +0200 CEST  1495   containerd
  2021-09-27 20:11:15.564011412 +0200 CEST  3563   containerd-shim
  2021-09-27 20:11:15.566385845 +0200 CEST  1603   kubelet
  2021-09-27 20:11:15.566485594 +0200 CEST  1603   kubelet
  2021-09-27 20:11:15.615859719 +0200 CEST  4261   k8s_metadata

复制

祝贺你,你已经成功地使用 Pixie 创建并部署了第一个 eBPF 程序!

从 Pixie UI 运行 sleepy_snoop

我们也可以使用 Pixie 的 UI[8]运行这个脚本:

  • 打开 Pixie 的 UI
  • 从顶部的 script 下拉菜单中选择 Scratch Pad。
  • 使用 ctrl+e(Windows,Linux)或 cmd+e(Mac)打开脚本编辑器,并粘贴上一节中的脚本。使用相同的键盘命令关闭编辑器。
  • 按下右上角的 RUN 按钮。

在一次成功的运行之后,你会在窗口的左边得到第一个结果,这将是一个表视图,有三个列:TIME_、PID 和 COMM。如前所述,这个 sleepy_snoop 跟踪所有调用 sleep 的 pid。你可以单击表行以查看 JSON 格式的行数据。

使用 OOM 杀手追踪点的真实演示

让我们再做一个例子,查找 OOM 终止的进程。简而言之,OOM 意味着内存不足,我们可以使用这里[9]找到的演示代码在 Kubernetes 集群上轻松地模拟这个情况。为了跟踪这些事件,我们将使用 oomkill.bt 工具。

让我们先看看原代码[10]

#include <linux/oom.h>

BEGIN
{
    printf("Tracing oom_kill_process()... Hit Ctrl-C to end.\n");
}

kprobe:oom_kill_process
{
    $oc = (struct oom_control *)arg0;
    time("%H:%M:%S ");
    printf("Triggered by PID %d (\"%s\"), ", pid, comm);
    printf("OOM kill of PID %d (\"%s\"), %d pages, loadavg: ",
        $oc->chosen->pid, $oc->chosen->comm, $oc->totalpages);
    cat("/proc/loadavg");
}

复制

如前所述,我们必须做一些小的调整,成为 PxL 脚本工作:

  • 首先,我们将开始删除 BEGIN 块,因为我们不需要这个 printf 语句。
  • 我们只能有一条 printf 语句,其中包含字段名作为实际输出到 Pixie 表,因此我们必须在 kprobe:oom_kill_process 块中组合这两条 printf 语句。
  • 我们删除了 time 函数,因为我们可以在字段名_time 原生使用 nsecs。
  • 我们删除了 cat 函数,因为它在 Pixie 中还不能使用。

eBPF 程序的最终应该如下所示:

kprobe:oom_kill_process
{
    $oc = (struct oom_control *)arg0;
    printf(\"time_:%llu triggered_by_pid:%d triggered_by_comm:%s killed_pid:%d killed_comm:%s pages:%d\",
           nsecs, pid, comm, $oc->chosen->pid, $oc->chosen->comm, $oc->totalpages);
}

复制

为了方便起见,我们可以使用 Pixie 现有的 bpftrace/oom_kill 脚本。从 UI 中的脚本下拉菜单中选择此脚本。

从 UI 的脚本菜单中选择 bpftrace/oom_kill。

现在运行脚本并查看是否有 OOM 事件发生。在正常情况下,你不应该看到任何 OOM 事件。

现在,让我们通过应用以下容器来触发 OOM 杀手:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: memleaky-app
spec:
  containers:
  - name: memleak
    image: avwsolutions/memleak:1.0
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

EOF

复制

几分钟后,由于内存限制,这个 pod 将获得状态 OOMKilled。

在 UI 中重新运行 PxL 脚本。

Pixie UI 中 bpftrace/oom_kill.pxl 的脚本输出。

现在我们可以看到哪个 pid 被杀死,由哪个 pid 和相应的名称触发。很酷,对吗?

更多 bpftrace PxL 脚本

要查看所有可用的脚本,请在 Pixie UI 的脚本下拉菜单中键入 bpftrace。我已经贡献了以下转换了的 bpftrace 程序:

bpftrace/capable

用于跟踪对内核 cap_capable 函数调用的工具。这个函数负责执行安全能力检查,在这里我们在 Pixie 表记录每次调用的所有细节。

bpftrace/dc_snoop

用于跟踪目录条目缓存(dcache)查找的工具。当你查找缓存命中(T=R)和缓存未命中(T=M)时,这很有帮助。

bpftrace/nap_time

使用 nanosleep 系统调用跟踪应用程序睡眠的工具。

bpftrace/sync_snoop

用于跟踪文件系统同步事件的工具,这些事件将文件系统缓冲区刷新到存储设备。

bpftrace/tcp_retransmits

用于跟踪由 tcp_retransmit()内核函数重传的网络流量 TCP 包并显示实际计数和相关会话信息的工具。多次重传表明网络连接不良,有助于诊断网络健康状况。

bpftrace/tcp_drop

用于跟踪由 tcp_drop()内核函数丢弃的网络流量 TCP 包的工具,并显示实际计数和相关会话信息。当你正在调查网络性能瓶颈时,当怀疑有高速率下降时,这可以帮助你。

总结

Pixie 是一个使 eBPF 更接近可观察性堆栈的应用程序调试平台。我希望这篇博客文章已经展示了 eBPF 的强大功能,以及使用 Pixie 将 BPF 程序部署到集群中的所有节点是多么容易。一定要查看 Pixie 中现有的所有 bpftrace 脚本,以及即将推出的实验性脚本[11]

我们也看到了这个特性的局限性。目前,只支持 KProbes,一些文档仍在制作中。希望这篇博客文章对文档部分有所帮助,并激励工程师或开发人员尝试 Pixie。对于社区来说,如果能够构建更棒、更有帮助的 PxL 脚本,那就太棒了。

在结束这个博客的时候,我们要向 Brendan Gregg 和 eBPF 社区鸣谢,感谢他们创造了这些很棒的 bpftrace 工具。最后,我想感谢来自 Pixie 的 Omid Azizi,感谢他的社区信念,并在创建这些脚本时对我的帮助。

资源

  • “使用 Pixie 部署分布式 bpftrace”教程[12]

有问题吗?可以在Slack[13]或推特上@pixie_run 找到我们。

参考资料

[1]

Pixie 是使用 Linux eBPF 技术构建的: https://docs.px.dev/about-pixie/pixie-ebpf/

[2]

原生跟踪的协议之外: https://docs.px.dev/about-pixie/data-sources/#supported-protocols

[3]

参考视频: https://www.youtube.com/watch?v=xT7OYAgIV28

[4]

IO Visor 项目: https://github.com/iovisor

[5]

小的调整: https://docs.px.dev/tutorials/custom-data/distributed-bpftrace-deployment/#output

[6]

sleepy_snoop.pxl 脚本: https://github.com/avwsolutions/app-debug-k8s-pixie-demo/blob/main/tracepoint-scripts/sleepy_snoop.pxl

[7]

教程: https://docs.px.dev/using-pixie/using-cli/

[8]

使用 Pixie 的 UI: https://docs.px.dev/using-pixie/using-live-ui/

[9]

OOM 演示代码: https://github.com/avwsolutions/app-debug-k8s-pixie-demo/tree/main/memleak

[10]

原代码: https://github.com/iovisor/bpftrace/blob/master/tools/oomkill.bt

[11]

实验性脚本: https://github.com/avwsolutions/app-debug-k8s-pixie-demo/tree/main/bpftrace-scripts-experimental

[12]

教程: https://docs.px.dev/tutorials/custom-data/distributed-bpftrace-deployment/

[13]

Slack: https://slackin.px.dev/


点击【阅读原文】阅读网站原文。


CNCF概况(幻灯片)

扫描二维码联系我们!




CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。 

CNCF云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。请长按以下二维码进行关注。

文章转载自CNCF,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论