Libbpf

Stella981
• 阅读 296

本篇文章概述了 BPF 的主要应用,重点描述了 libbpf-tools 解决了哪些 BCC 痛点以及在 PingCAP 内部的相关实践

BPF 最初代表 Berkeley Packet Filter,但在 Linux 中已扩展为通用内核执行引擎,能够运行新型的用户定义和内核模式应用程序。近几年来,BPF 子系统越发火热,迄至 Linux 5.8 内核,Linux 内核已经支持 30 种 eBPF 程序类型,遍布于内核各个角落,引起了广泛关注及热议,在 LWN 上甚至出现过 Why don't we rename Linux to BPF-kernel? 这样的嘲讽评论,不过更多的是一些理性的讨论。除上周在 CNCF 和大家分享的 BPF 在 Chaos 领域的应用外,目前 BPF 主要应用于:

  1. 跟踪和探测,最有名的应用当属 BCC;

  2. 网络功能 (XDP/TC),用于反 ddos,负载均衡等,K8S 平台有著名的 Cilium;

  3. 内核安全策略;

  4. 内核回调接口,这种新架构可用于允许 BPF 程序替换内核中的任何 “ops 结构 ( struct xxx_ops ) ,社区大佬对此功能的评价是:march towards becoming BPF runtime-powered microkernel,目前 TCP 拥塞算法已用此框架实现,感兴趣的可以体验下;

  5. 迭代器:dump 内核数据;

  6. … …

这些功能都非常酷,其中上述一些应用的背后有着一个重要的基础功能 BTF 做支撑, BTF 的一个用途是实现 BPF CO-RE (Compile Once – Run Everywhere)重定向,我们来看下如何基于 BPF CO-RE 替代 BCC 工具来获得更好的体验。

Libbpf-tools vs BCC

BCC 是 BPF 的编译工具集合,前端提供 Python/Lua API,本身通过 C/C++ 语言实现,集成 LLVM/Clang 对 BPF 程序进行重写、编译和加载等功能, 提供一些更人性化的函数给用户使用。

虽然 BCC 竭尽全力地简化 BPF 程序开发人员的工作,但其“黑魔法” (使用 Clang 前端修改了用户编写的 BPF 程序)使得出现问题时,很难找到问题的所在以及解决方法。必须记住命名约定和自动生成的跟踪点结构 。且由于 libbcc 库内部集成了庞大的 LLVM/Clang 库,使其在使用过程中会遇到一些问题:

  1. 在每个工具启动时,都会占用较高的 CPU 和内存资源来编译 BPF 程序,在系统资源已经短缺的服务器上运行可能引起问题;

  2. 依赖于内核头文件包,必须将其安装在每个目标主机上。即便如此,如果需要内核中未 export 的内容,则需要手动将类型定义复制/粘贴到 BPF 代码中;

  3. 由于 BPF 程序是在运行时才编译,因此很多简单的编译错误只能在运行时检测到,影响开发体验。

随着 BPF CO-RE 的落地,我们可以直接使用内核开发人员提供的 libbpf 库来开发 BPF 程序,开发方式和编写普通 C 用户态程序一样:一次编译生成小型的二进制文件。Libbpf 作为 BPF 程序加载器,接管了重定向、加载、验证等功能,BPF 程序开发者只需要关注 BPF 程序的正确性和性能即可。这种方式将开销降到了最低,且去除了庞大的依赖关系,使得整体开发流程更加顺畅。

性能优化大师 Brendan Gregg 在用 libbpf + BPF CO-RE 转换一个 BCC 工具后给出了性能对比数据:

As my colleague Jason pointed out, the memory footprint of opensnoop as CO-RE is much lower than opensnoop.py. 9 Mbytes for CO-RE vs 80 Mbytes for Python.

我们可以看到在运行时相比 BCC 版本,libbpf + BPF CO-RE 版本节约了近 9 倍的内存开销,这对于物理内存资源已经紧张的服务器来说会更友好。

Libbpf-tools 在 PingCAP 的应用

在 PingCAP 内部,我们很早就开始关注 BPF 和其社区发展,以前每添加一台新机器,就得在上面安装一套 BCC 依赖,比较麻烦,自从 libbpf-tools 示例程序添加到 BCC 项目后,我们就开始转换体验,在此过程中有幸得到了 Andrii Nakryiko (libbpf + BPF CO-RE 的主导者),和 Brendan Gregg,Yonghong Song 的指导。当前已完成 10 个 BCC/bpftrace 工具到 libbpf + BPF CO-RE 的转换 & 改进,并在内部使用。比如当需要弄清特定 workload 下 IO 特征时,就可以使用 block 层的多个性能分析工具来分析:

  1. 使用 ./biolatency -d nvme0n1 确认 IO 请求的延迟分布情况:

    Libbpf

  2. 使用 ./biopattern -T 1 -d 259:0 分析 IO 模式:

    Libbpf

  3. 使用 ./bitesize -c fio -T 确认 task 下发物理 IO 请求时的请求大小分布图:

    Libbpf

  4. 使用 ./biosnoop -d nvme0n1 对每次物理 IO 都进行详细都分析:

    Libbpf

这些分析结果为后续的 IO 优化提供指导建议。除此之外,我们也在探索调度器相关的 libbpf-tools 对 TiDB 数据库的调优是否有帮助。这些工具属于通用型工具,欢迎大家来使用!

后续会将更多的工具基于 libbpf-tools 的方式来实现。期待大家的使用反馈!

点赞
收藏
评论区
推荐文章
刚刚好 刚刚好
2个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
晴空闲云 晴空闲云
2个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
Karen110 Karen110
1年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
艾木酱 艾木酱
1个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Easter79 Easter79
1年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
Easter79 Easter79
1年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序selectfromtable_nameorderiddesc;2.按照指定(多个)字段排序selectfromtable_nameorderiddesc,statusdesc;3.按照指定字段和规则排序selec
Wesley13 Wesley13
1年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
helloworld_34035044 helloworld_34035044
5个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
helloworld_28799839 helloworld_28799839
2个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue