共计 2854 个字符,预计需要花费 8 分钟才能阅读完成。
近日,在 2022 云栖大会龙蜥峰会 eBPF & Linux 稳定性专场上,来自 eBPF 技术摸索 SIG Maintainer 的毛文安分享了《Coolbpf 的利用实际》技术演讲,以下为本次演讲内容:
一、为什么要反对可移植?
随着 BPF 技术的倒退,开发一个 BPF 程序变得越来越简略,只管 BPF 晋升了便利性,但 BPF 也始终在谋求另一个方面:可移植性。BPF 可移植性被定义为胜利编写并通过内核验证的一个 BPF 程序,能运行在不同内核版本。
进行 BPF 的移植有两个挑战:
- 不同内核版本数据的内存布局不同。
- 内核类型和数据结构一直变动,构造体字段可能被移除或重命名。
BPF CO-RE(Compile Once – Run Everywhere) 是实现可移植性的一个伎俩。
为了反对 CORE,提供了以下组件:
- BTF:形容内核镜像,获取内核及 BPF 程序类型和代码的要害信息
- Clang 开释 bpf 程序重定位信息到.btf 段
- Libbpf CO-RE 依据.btf 段重定位 bpf 程序
须要进行重定位的信息次要有三类:
- 构造体相干重定位,这部分和 BTF 非亲非故。Clang 通过__builtin_preserve_access_index() 记录成员偏移量。
- map fd、全局变量(data、bss、rodata)、extern 的变量重定位,次要依赖于 ELF 的重定位机制,来更新 eBPF 指令的 imm 字段。
- 子函数重定位,是为了将 eBPF 程序调用的子函数同主函数放在一起,便于一起加载到内核。
应用 libbpf 进行 BPF CORE 的开发步骤如下:
1. 生成带所有内核类型的头文件 vmlinux.h,通过 bpftool 生成。
- 应用 Clang(版本 10 或更新版本) 将 BPF 程序的源代码编译为 .o 对象文件;
- 从编译好的 BPF 对象文件中生成 BPF skeleton 头文件 bpftool gen 命令生成;
- 在用户空间代码中蕴含生成的 BPF skeleton 头文件;
- 编译用户空间代码,则嵌入 BPF 对象代码无需公布独自的文件。
大抵有如下的函数调用:
<name>__open():创立并关上 BPF 利用,之后能够设置 skel->rodata 变量。
<name>__load():初始化,加载和校验 BPF 利用局部。
<name>__attach():附加所有能够主动附加的 BPF 程序。有事件和网络运行报文达到时,会触发运行 bpf 程序。
<name>__destroy():拆散所有的 BPF 程序并应用其应用的所有资源。
eBPF 程序的次要开发方式有三种,它们各有优缺点,见下:
1、内核自带示例代码:基于内核 samples/bpf 示例代码,无 CORE。该形式没有任何基于第三方的开源我的项目,资源占用量低。但毛病是须要本人齐全从新搭建工程,效率较低,且版本兼容性较差。
2、BPF CORE:基于 libbpf 本人编写的 bpf_core_read 代码,开发机生成对应指标机的二进制程序。该形式不依赖在环境中部署 Clang/LLVM,资源占用少。然而须要搭建编译工程,局部代码绝对固定,无奈动静配置。
3、BCC:基于利用最广的开源我的项目,开发效率较高。然而每一次运行都要执行 Clang/LLVM 编译,存在内存、CPU 等资源的争抢;指标环境依赖对应内核头文件。
二、Coolbpf 的性能和架构
Coolbpf 提供了近程编译(云编译)。其中近程编译指运行程序的指标机器与编译程序不在同一个机器上,可能解决资源占用问题;提供了本地编译和根底库封装,不便用户调用根底库进行编写;提供了低版本内核的反对;提供了 BTF 的主动生成和公布,用户无需手动适配,下载即可间接应用;提供了自动化测试以及反对 Python/Go/Rust 等高级语言进行利用开发。
Coolbpf 人造反对 BPF 的 CORE 能力,它解决了编译和资源耗费的问题,同时,后面介绍的简单的 libbpf 开发步骤齐全被简化了。用户只须要专一本人的性能开发,不必关注环境搭建和冗余代码开发。
Coolbpf 提供了标准化的 bpf 编译服务。首先将 bpf.c 提交到近程编译服务器时,服务器会依据的内核版本针对不同的语言返回点 bpf.so 或 bpf.o 为高级的应用程序提供服务。因而在你的高级语言代码中,只需加载 bpf.so 即可运行程序,无需再手动触发 Libbpf 的 open()、load()、attach() 等函数,而是由高级语言程序的 init() 主动实现,这样用户能够疾速搭建和部署工程,只需专一于数据输入之后的解决。
Coolbpf 还反对在没有 eBPF 个性的低内核版本上,通过咱们提供的 eBPF 驱动,帮忙它平安的在低版本上运行。咱们将高版本上 eBPF verifier 校验局部实现在一个驱动里,它会进行各种平安校验,保障 eBPF 比照于内核模块的安全性。另外,咱们把原来基于 libbpf 的调用都转换为 IOCTL 的零碎调用。
之前反对的 helper 函数、创立 map、加载 program 都会转化成低版本上的 kprobe 或 tracepoint 的实现,另外还反对 perf event 和 jit。这样就使得同一个用户程序,加载这样一个驱动,就能不批改 eBPF 程序代码而平安的运行在低版本内核上。
三、Coolbpf 的网络应用实际
Raptor 是基于 Coolbpf 的零碎可观测工具,可能运行在低版本内核如 alios、CentOS 3.10 等。它能够作为一个 SDK,提供给第三方应用,进行数据采集。
在这个网络应用观测中,通过监控零碎调用中的数据交互、申请和回复等信息,来确定交互的数据内容和五元组等信息,通过 map 的交互方式发送给用户态,做到了无侵入的形式做观测,最终出现比方流量统计、申请时延等观测后果。
咱们来看一个具体的问题,理解 Coolbpf 是如何发现收包阶段的网络抖动问题。咱们晓得网络收包分为两个阶段:
阶段 1:OS 通过软中断将数据包送到利用的收包队列并告诉过程,实现协定栈的收包工作。
阶段 2:利用失去告诉后从收包队列取数据。
咱们在 Coolbpf 里写一段 BPF 程序,只需监控两个 tracepoint:tcp_probe,tcp_rcv_space_adjust 就能查问到阶段 2 的提早问题。
在这个案例中,某业务利用收包慢,发现内核侧曾经收到了 tcp 包,然而利用侧将近 1s 后才收到。
观测办法:部署 eBPF agent,发现阶段 2“收包延迟时间”将近 1 秒。
确定起因:每次产生延迟时间都在某时刻的大抵 42 秒处,狐疑跟业务某定时工作相干造成利用本身延时,最终排查到业务有某个工作会定时收集 jvm 的参数,对该业务有 stop 的操作。
解决办法:停掉该工作后,打消了抖动问题。
相干链接:
eBPF 技术摸索 SIG 地址:https://openanolis.cn/sig/ebp…
对于龙蜥峰会 eBPF & Linux 稳定性专场课件获取形式:
【PPT 课件获取】:关注微信公众号(OpenAnolis),回复“龙蜥课件”即可获取。有任何疑问请随时征询龙蜥助手—小龙(微信:openanolis_assis)。
【视频回放】:视频回放可返回龙蜥官网查看。
—— 完 ——