目录
目录README.md

Zoltraak

1 背景与目标

1.1 背景

ebpf 是一种新兴的内核技术,使开发者能够在内核级别收集和分析系统性能数据。通过 eBPF,可以监控各种内核事件,例如系统调用、上下文切换、进程调度、文件系统操作等,而无需修改应用程序代码或重启系统。eBPF 程序可以附加到特定的内核探针(如 kprobe 和 tracepoint),实时收集详细的运行时信息,将其传输到用户空间,并生成更高层次的性能分析和可视化数据。这种实时、低开销的可观测性使得 eBPF 成为监控和调试 Linux 系统的关键技术,广泛应用于性能调优和故障排查等场景。

目前,ebpf 社区主流的开发工具有 BCC、libbpf,主流的诊断工具有 BCC examples、bpftraces 等。基于 BCC 开发框架在部署上比较方便,但运行环境需要安装完整工具链,并且在部署时需要现场编译,性能开销过高;基于libbpf的原生开发方案ebpf程序运行性能开销低,但 C/C++ 开发难度较大,对开发人员不友好。ebpf 社区开发了基于 Go 语言与 Rust 语言的原生开发框架,但也只针对特定语言。

在容器异常检测上,我们主要针对混部场景的容器资源竞争进行检测。基于监督学习的方法需要大量标注好的训练数据,覆盖工作负载有限,较难落地;无监督学习方法根据历史数据模式识别异常,正确率有限。结合 ebpf 的可观测性功能,以及对性能异常数据检测工具的调研,我们提出以下 3 个观点:

  1. 机器学习方法适合上层 SLO 指标,例如 CPU 利用率、响应延迟、内存占用等,且此类方法基于训练数据或者是历史数据的稳定性,对混部这一复杂场景效果未知;
  2. ebpf 的引入是为了采集上层工具难以采集到数据指标,或者降低原有工具的开销;
  3. 混部场景的容器异常检测更加适合使用领域特定知识。

1.2 目标

题目初始的目标有 4 项,Zoltraak 全部完成:

  1. 性能开销低,要求为 CPU 开销 < 10%, Zoltraak 采集器开销的 CPU 开销 < 1%;
  2. 拥有准确的异常监测算法,Zoltraak 基于领域知识提出容器间的 CPU 资源竞争监测算法,以及锁阈值与OOM事件检测;
  3. 拥有清晰易懂的可视化界面,Zoltraak 自研可视化界面,展示性能数据与异常检测数据。
  4. 可拓展性,Zoltraak 既能通过 Json 文件配置已有的 ebpf 采集功能,也方便开发进行二次开发。

对于目标 1, Zoltraak 使用基于 libbpf 的原生框架开发,在 JIT 预热之后 CPU 开销 < 1%;

对于目标 2,Zoltraak 设计了丰富的性能指标,可供可观测数据平台分析使用。同时开发了精准的异常检测算法。详见 2.1 与 2.2。

对于目标 3,Zoltraak 自研了基于 Echarts 的可视化界面,方便查看性能数据与异常检测结果。

对于目标 4,Zoltraak 设计了基于动态库的 ebpf 程序部署方式,可以给多种编程提供服务,将 ebpf 程序开发与指标数据存储处理开发工作解耦。并且,Zoltraak 框架保留了原生libbpf的性能优势,在添加 ebpf 功能时,ebpf 开发人员暴露相关接口,由上层开发人员调用接口启动并对ebpf数据进行读取。另外,Zoltraak 也能基于 Json 配置文件配置已开发的功能。

2 实现

2.1 指标采集

Zoltraak 的指标设计有几点原则:

  1. 轻量,对上层应用的影响尽可能小;
  2. 支持对容器资源消耗的持续监测,遵循 Richard L. Site 对性能资源的 5 大分类,即 CPU、内存、硬盘、网络与锁;
  3. 仅采集 ebpf 适合采集的数据,例如 PMU 数据,通过 sysfs 暴露的性能数据,使用 ebpf 采集并没有显著优势;
  4. 足够支撑 Zoltraak 框架设计的异常监测功能实现。

基于以上原则,Zoltraak 实现了如下指标的采集:

  1. CPU 资源:容器每个核心的 CPU 利用率(区分用户利用率与系统利用率),Context Switch 次数,SysCall Yield 次数;
  2. 内存资源:Page Fault 次数,区分用户与内核,OOM 事件捕获与原因记录;
  3. 硬盘:SysCall Sync 与 Fsync 次数;
  4. 网络:TCP RX TX 流量,TCP RTT 直方图,以及与网络相关的系统调用次数;
  5. 锁:调用 Syscall Futex,Semop 的次数与时间。

Zoltraak 做到容器每个 CPU 核心利用率指标的采集。多数可观测性框架没有实现这一特性,使用聚合后的 CPU 利用率,但聚合后的数据不足以支撑性能分析与异常检测。

Zoltraak 所有指标按照容器为单位进行划分。

ebpf 在容器内存性能监测上能力较弱,建议使用 Linux 5.15 引入的 DAMON 特性,而不是使用 ebpf。

2.2 异常检测

Zoltraak 实现了基于无监督离线学习的脚本进行异常监测,并在实验数据上验证的了算法正确性。但如同 1.1 中所述,我们不推荐使用机器学习方法,故仅提供脚本代码作为参考。

2.2.1 CPU 资源竞争检测

BCC examples 提供的 CPU 资源竞争检测是通过 runqueue length 这一指标进行评估;Netfix 则使用 runqueue latency 与 context switch out 2 个指标对容器间的 CPU 资源竞争进行评估。Zoltraak 采集 context switch out,并基于该数据建立有向图,使用 Tarjan 算法获取有向图的强连通分量。当强连通分量内点的个数 > 1 时,可以认为发生了 CPU 资源竞争。节点中的边权信息是 context switch out 次数,其代表 CPU 资源竞争的激烈程度。根据节点出入度与应用类别(延迟敏感/批处理),上层调度器可以实现简单的调度算法处理该异常。

相较于 BCC examples 的方案,Zoltraak 方案的优势是:

  • runqueue length 不能直接反映 CPU 资源竞争程度,且无法通过 runqueue length 指导混部调度器对容器中的进程进行调离;

相较于 Netfix 容器干扰邻居检测,Zoltraak 的优势是:

  • Zoltraak 仅需要对 switch_sched 函数进行插桩,Netfix 则需要额外 2 个插桩点。并且,Netfix 没有基于图的数据建模方式,基于延迟时间指标难以进行归一化(延迟敏感应用与批处理任务需要在延迟数据的处理上需要不同的基准)。

Netfix 与 Zoltraak 都采集了 context switch out 这一指标,但是,Zoltraak 与 Netfix 都是独立提出这一指标的。Zoltraak 不是基于 Netfix 方案进行改良,而是在初赛时就完成了该方案的主体设计。Netfix 容器干扰邻居检测方法的博文是 2024.9.11 提出,比 Zoltraak 初赛提交晚 1 个月。

2.2.2 锁阈值检测与 OOM 检测

Zoltraak 框架可以采集陷入 Syscall Futex 与 Semop 的时间,该时间与墙上时间的比值,可以一定程度上反映对锁的利用程度。当高于某个阈值时,可以认为锁使用上发生了异常。

Zoltraak 也能捕获 OOM 事件,该事件是异常事件,ebpf 可以采集 OOM 发生时的函数栈,内存页数量与触发 OOM 的原因。上层调度器可有根据原因与内存页数量判断该程序是存在内存泄漏 BUG 或者是由于容器配置异常所致。

ebpf 功能拓展

ebpf 程序与可观测数据平台代码之间的融合是一个棘手的问题,有几种方案:

  1. 使用集成方案,在原有框架上二次开发,比如在 Pixie 的基础上添加功能,该方法难以迁移到已有的性能监控平台;
  2. 使用 BCC,bpftrace 进行开发,降低 ebpf 程序开发与部署难度,但会增加 ebpf 程序运行性能开销;
  3. 使用 libbpf及其变体原生开发,对 ebpf 程序开发人员要求提高,同时限制编程语言的使用;
  4. 使用 eunomia-bpf 原生开发后使用 wasm 打包部署,降低部署难度,但 wasm 运行时性能相较于主流 JIT 运行时(JVM、dotnet)仍有差距。

针对以上框架和问题,我们有以下思考:

  1. 对于持续性性能监测,性能采集器的性能是至关重要的,原生开发可以保证性能开销较低;
  2. ebpf 程序的正确实现依赖于开发人员对 Linux 内核的认知水平,一味降低开发难度可能适得其反,ebpf 程序开发的灵活性至关重要;
  3. C ABI 十分稳定,主流语言均可调用 C 语言开发的库接口;
  4. libbpf 对跨平台支持较为友好。

Zoltraak 的解决方案,是 ebpf 开发人员开发 ebpf 程序,并暴露出 API 供其他程序调用。这样部署时只需要在目标机器上添加一份动态链接库文件即可。上层监控平台人员通过接口启动 ebpf 程序并采集性能数据。具体到 Zoltraak 实现上,ebpf 程序仅需要暴露 start,read,clean_up 完成对上层框架的对接。上层程序仅需要实现 Manager 的子类,调用对应接口完成启动到采集数据,存储到数据库整个过程。Zoltraak 框架设计完成了 ebpf 开发与上层监控平台开发的解耦

Zoltraak ebpf 侧使用 libbpf 原生开发,上层数据采集与处理使用 dotnet8,时序数据库使用 Influxdb2.7。得益于 C ABI 的稳定性,Zoltraak 提出的 ebpf 程序开发与部署方案适用于绝大多数语言,可以迁移到其他平台上。

3 使用

在 oos_ebpf 目录下,输入如下指令

bash go.sh

influxdb 的配置信息在 config/influx.json 中编辑,需要有 metrics 与 abnormal 2 个 bucket。

启动 Zoltraak 采集器指令如下所示:

# 这是 DEBUG 模式运行,会打印采集到的数据与一些额外信息
sudo LD_PRELOAD=lib/libbpf.so dotnet run config/test.json config/influx.json

# 这是 Release 模式运行,不会打印额外信息
sudo LD_PRELOAD=lib/libbpf.so dotnet run config/test.json config/influx.json -c Release

启动可视化 Web 程序命令如下所示:

python src/Web/main.py

4 测试

4.1 测试环境

环境 说明
系统 Ubuntu 23.10
CPU 虚拟核心数 16
Linux 内核版本号 6.5
libbpf 版本 1.5
dotnet 版本 8.0.107
是否为虚拟机 是,基于 KVM

4.2 测试软件

我们通过 iperf3 与 SPECCPU 2017 602.gcc 工作负载评价。分别运行在 Zoltraak 未启动与 Zoltraak 启动时运行负载,对比运行时间与输出的性能指标。

# iperf3 启动命令 (运行 Zoltraak 的机器)
iperf3 -s

# iperf3

# SPECCPU2017 602.gcc 输入数据为 train,使用 time 采集运行时间

4.3 测试结果

602.gcc 运行 3 次采集运行时间测试结果。 | Zoltraak 是否开启 | 602.gcc 平均运行时间 | | :—————: | :——————: | | 否 | 44.703 sec | | 是 | 44.288 sec |

iperf3 运行 60 秒,获取 iperf3 输出的带宽指标。 | Zoltraak | iperf3 Receiver Bitrate | | ——– | :———————: | | 否 | 17.4 Gbits/sec | | 是 | 18.2 Gbits/sec |

Zoltraak 开启后性能指标有细微提升,可以认为是系统误差。基于上述实验结果,可以认为 Zoltraak 具有极低的性能开销,适合作为可观测性工具使用。

关于
71.1 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

©Copyright 2023 CCF 开源发展委员会
Powered by Trustie& IntelliDE 京ICP备13000930号