最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

Wasm-bpf: 为云原生 Webassembly 提供通用的 eBPF 内核可编程能力

  • 2023-02-25
    北京
  • 本文字数:5433 字

    阅读完需:约 18 分钟

Wasm-bpf: 为云原生 Webassembly 提供通用的 eBPF 内核可编程能力

Wasm-bpf 由 eunomia-bpf 社区发起,该社区是阿里龙蜥社区 eBPF 技术探索 SIG 中孵化的一个探索性的社区开源项目,在 2022 年九月份发起,主要关注于简化 eBPF 程序的编写、分发,以及探索 eBPF 和 Wasm 相结合的工具链、运行时等技术。


目前 eunomia-bpf 开源社区主要由西安邮电大学陈莉君教授,来自阿里云、腾讯等的国内外 eBPF 领域知名专家担任 Maintainer,团队也包含来自 deepflow 等多个企业的工程师,和多位内核贡献者。社区目前也由中科院软件所程序语言与编译技术实验室(PLCT)赞助和持续维护,其中包含的一些工具链项目也在阿里云的 eBPF 开发框架 Coolbpf、三度观测云等企业项目中落地和使用。


Wasm 最初是以浏览器安全沙盒为目的开发的,发展到目前为止,WebAssembly 已经成为一个用于云原生软件组件的高性能、跨平台和多语言软件沙箱环境,Wasm 轻量级容器也非常适合作为下一代无服务器平台运行时。另一个令人兴奋的趋势是 eBPF 的兴起,它使云原生开发人员能够构建安全的网络、服务网格和多种可观测性组件,并且它也在逐步渗透和深入到内核的各个组件,提供更强大的内核态可编程交互能力。


Wasm-bpf 是一个全新的开源项目[1],它定义了一套 eBPF 相关系统接口的抽象,并提供了一套对应的开发工具链、库以及通用的 Wasm + eBPF 运行时平台实例,让任意 Wasm 虚拟机或者 Wasm 轻量级容器中的应用,有能力将使用场景下沉和拓展到内核态,获取内核态和用户态的几乎所有数据,在网络、安全等多个方面实现对整个操作系统层面的可编程控制,从而极大的拓展 WebAssembly 生态在非浏览器端的应用场景。

基于 eBPF 的系统接口,为 Wasm 带来更多可能


也许你也已经看过 Solomon Hykes (Docker 的创始人之一)这句话:


如果在 2008 年已经有了 WASM + WASI,我们根本不需要创建 Docker。 Wasm 就有这么重要。 服务端的 WebAssembly 是计算的未来。


因为无法依赖浏览器中现有可用的 JavaScript 引擎接口,所以目前大多数在浏览器外运行的 Wasm 轻量级容器需要使用 WASI(WebAssembly 系统接口)。这些运行时允许 Wasm 应用程序以与 POSIX 类似(但不完全相同)的方式与其 host 操作系统交互。


但是,相对于传统的容器中可以使用几乎所有的系统调用,目前 WASI 所能提供的系统资源非常有限,目前仅仅在文件系统、socket 网络连接等方面提供了一些基本的支持,对于操作系统底层资源的访问、控制和管理能力仍然存在大量空白,例如对 Wasm 模块或者外部其他进程的执行资源限制与行为观测,对网络包的快速转发和处理,甚至和 wasm 沙箱外的其他进程进行通信,访问外设等,都没有一个比较成熟的解决方案。这也使得大多数的 Wasm 轻量级容器在实际应用中还是主要集中于纯粹的计算密集型应用,而在网络、安全等方面,还是需要依赖于传统的容器技术。


这也是我们希望建立 Wasm-bpf 项目的初衷:借助当前内核态 eBPF 提供的系统接口以及和用户态交互的能力,拓展整个 WASI 的生态蓝图,为 Wasm 应用带来更多可能的使用场景,同时也能在用户态增强 eBPF 程序的能力。


或者换句话说,类似于浏览器中运行的 Wasm 程序,通过 JavaScript 引擎接口访问浏览器提供的各种系统资源,Wasm-bpf 的方案就是借助 eBPF 虚拟机访问操作系统的各类资源;得益于 eBPF 目前在 Linux 内核甚至 Windows 等其他操作系统中的广泛支持,以及不同内核版本和架构之间的可移植性,和内核 BPF 验证引擎的可靠性,我们仍然可以在一定程度上保证应用的可移植性和安全边界。


Wasm-bpf 项目已经实现了内核态 eBPF 虚拟机和用户态之间系统接口完整的抽象机制,并提供了对应的工具链以将 eBPF 应用编译为 Wasm 模块,帮助进行内核态 eBPF 和用户态 Wasm 之间无序列化,共享内存的高效双向通信,并通过代码生成技术,提供和其他用户态 eBPF 开发框架几乎一致的、简单便捷的开发体验。借助 Wasm 组件模型不断完善的生态支持,我们也可以为 eBPF 社区带来更多用户态开发语言,不同语言实现的可观测性、网络等 eBPF 应用和数据处理插件也可以被轻松集成、复用、统一管理。


在几乎已经成为 eBPF 用户态事实上的 API 标准的 libbpf 库,和 WAMR(wasm-micro-runtime) 之上,只需要 300+ 行代码即可构建完整的通用 Wasm-eBPF 运行组件,并支持大多数的 eBPF 使用场景 -- 任何人用任何主流 Wasm 运行时,或者任何 eBPF 用户态库,以及任何编程语言,都可以轻松添加对应的虚拟机支持,并复用我们的工具链轻松实现 Wasm-eBPF 程序的编写和开发。


之前在 eunomia-bpf 项目中,已经有一些将 eBPF 和 Wasm 结合的探索,但它并不是为了 Wasm 原生应用的场景设计的,不符合 Wasm-eBPF 的通用编程模型,性能也较为低下,因此我们创建了一个新的开源仓库,让 Wasm-bpf 项目专注于利用 eBPF 增强和扩展 WebAssembly 使用场景,并进一步完善对应的工具链和开发库支持:https://github.com/eunomia-bpf/wasm-bpf

eBPF 能给 Wasm 带来什么?

eBPF 是一项革命性的技术,起源于 Linux 内核,可以在操作系统的内核中运行沙盒程序。它被用来安全和有效地扩展内核的功能,而不需要改变内核的源代码或加载内核模块。


从历史上看,由于内核具有监督和控制整个系统的特权能力,所以操作系统一直是实现可观察性、安全性和网络功能等多种能力的理想场所。同时,由于操作系统内核对稳定性和安全性的高要求,内核的新功能迭代通常非常谨慎,也很难接受自定义的、较少通用性的功能改进。因此,与用户态的更多功能相比,内核态操作系统层面的创新率历来都比较低[2]。



eBPF 从根本上改变了这个公式。通过允许在操作系统内运行沙盒程序,应用程序开发人员可以在运行时,可编程地向操作系统动态添加额外的功能。然后,操作系统保证安全和执行效率,就像在即时编译(JIT)编译器和验证引擎的帮助下进行本地编译一样。eBPF 程序在内核版本之间是可移植的,并且可以自动更新,从而避免了工作负载中断和节点重启。


今天,eBPF 被广泛用于各类场景:在现代数据中心和云原生环境中,可以提供高性能的网络包处理和负载均衡;以非常低的资源开销,做到对多种细粒度指标的可观测性,帮助应用程序开发人员跟踪应用程序,为性能故障排除提供洞察力;保障应用程序和容器运行时的安全执行,等等。可能性是无穷的,而 eBPF 在操作系统内核中所释放的创新才刚刚开始[3]。

eBPF 的未来:内核的 JavaScript 可编程接口

对于浏览器而言,JavaScript 的引入带来的可编程性开启了一场巨大的革命,使浏览器发展成为几乎独立的操作系统。现在让我们回到 eBPF:为了理解 eBPF 对 Linux 内核的可编程性影响,对 Linux 内核的结构以及它如何与应用程序和硬件进行交互有一个高层次的理解是有帮助的。



Linux 内核的主要目的是抽象出硬件或虚拟硬件,并提供一个一致的 API(系统调用),允许应用程序运行和共享资源。为了实现这个目的,我们维护了一系列子系统和层,以分配这些责任。每个子系统通常允许某种程度的配置,以考虑到用户的不同需求。如果不能配置所需的行为,就需要改变内核,从历史上看,改变内核的行为,或者让用户编写的程序能够在内核中运行,就有两种选择:


本地支持内核模块写一个内核模块
改变内核源代码,并说服Linux内核社区相信这种改变是必要的。等待几年,让新的内核版本成为一种商品。定期修复它,因为每个内核版本都可能破坏它。由于缺乏安全边界,冒着破坏你的Linux内核的风险


实际上,两种方案都不常用,前者成本太高,后者则几乎没有可移植性。


有了 eBPF,就有了一个新的选择,可以重新编程 Linux 内核的行为,而不需要改变内核的源代码或加载内核模块,同时保证在不同内核版本之间一定程度上的行为一致性和兼容性、以及安全性。为了实现这个目的,eBPF 程序也需要有一套对应的 API,允许用户定义的应用程序运行和共享资源 --- 换句话说,某种意义上讲 eBPF 虚拟机也提供了一套类似于系统调用的机制,借助 eBPF 和用户态通信的机制,Wasm 虚拟机和用户态应用也可以获得这套“系统调用”的完整使用权,一方面能可编程地扩展传统的系统调用的能力,另一方面实现更高效的可编程 IO 处理。


目前的 eBPF 仍然处于早期阶段,但是借助当前 eBPF 提供的内核接口和用户态交互的能力,经由 Wasm-bpf 的系统接口转换,Wasm 虚拟机中的应用已经有能力获取内核以及用户态任意一个函数调用的数据和返回值;以很低的代价收集和理解所有系统调用,并获取所有网络操作的数据包和套接字级别的数据;在网络包处理解决方案中添加额外的协议分析器,并轻松地编程任何转发逻辑,以满足不断变化的需求,而无需离开 Linux 内核的数据包处理环境。


所有的这些场景都不需要离开 Wasm 轻量级容器:不像传统的使用 Wasm 作为数据处理或者控制插件的应用中,这些步骤由 Wasm 虚拟机外的逻辑实现,现在可以在 Wasm 轻量级容器中实现对 eBPF 以及 eBPF 能访问的几乎所有系统资源,完整的控制和交互,甚至实时生成 eBPF 代码改变内核的行为逻辑,实现整个系统从用户态扩展到内核态的可编程性。

用户空间和 eBPF 程序的交互流程

eBPF 程序是以函数为单位的、事件驱动的,当内核或用户空间应用程序通过某个 hook 点时就会运行特定的 eBPF 程序。要使用一个 eBPF 程序,首先我们需要使用 clang/LLVM 工具链将对应的源代码编译为 bpf 字节码,其中包含对应的数据结构定义、maps 和 progs 定义,progs 即程序段,maps 可以用来存储数据或者和用户空间实现双向通信。之后,我们可以借助用户态的开发框架和加载框架,实现完整的 eBPF 应用。

通常的用户态 eBPF 开发框架

对于一个完整的 eBPF 应用,通常需要包含用户态和内核态两部分:


  • 用户态程序需要通过一系列系统调用跟内核进行交互(主要是 bpf 系统调用),创建对应的 map 以在内核态保存数据或和用户态通信,根据配置动态选择加载不同的程序段,动态修改字节码或配置 eBPF 程序的参数,将对应的字节码信息加载进内核,通过验证器确保安全性,并通过 maps 和内核之间实现双向通信,通过 ring buffer / perf buffer 之类的机制从内核态向用户态传递数据(或者反之)。

  • 内核态主要负责具体的计算逻辑与数据收集。



在用户态 Wasm-eBPF 系统接口之上定义的全新 eBPF 开发框架

这个项目本质上可以说是希望把 Wasm 沙箱当做在操作系统之上建立的另一个用户态运行空间,让 Wasm 应用在沙箱中实现和通常用户态中运行的 eBPF 应用一样的编程模型和执行逻辑。Wasm-bpf 会需要一个在 host(沙箱外部)构建的运行时模块,以及一些在沙箱内部被编译为 Wasm 字节码的运行时库来提供完整的支持。



要实现完备的开发模型,我们需要:


  • 一个 Wasm 模块可以对应多个 eBPF 程序;

  • 一个 eBPF 程序实例也可以被多个 Wasm 模块所共用;

  • 可以将 eBPF 程序从 Wasm 沙箱中动态加载进内核、选择所需的挂载点挂载、卸载,控制多个 eBPF 字节码对象的完整生命周期,并支持大多数的 eBPF 程序类型;

  • 可以通过多种类型的 Maps 和内核双向通信,支持大多数的 Maps 类型;

  • 通过 ring buffer 和 perf event polling 从内核态向用户态高效发送信息(对于 ring buffer 来说,也可以反之);

  • 几乎可以适配于所有的使用 eBPF 程序的应用场景,并可以随着内核功能的添加不断演化和扩展,同时不需要变动 Wasm 虚拟机的系统接口。


这就是目前 Wasm-bpf 项目所做的工作。我们也提出了一个新的 WASI 的 Proposal: WASI-eBPF[7].


在 Wasm-bpf 项目中,所有 Wasm 和 eBPF 虚拟机之间的通信都无需经过序列化、反序列化机制,通过工具链中代码生成技术和 BTF(BPF 类型格式[7])信息的支持,我们可以实现在 eBPF 和 Wasm 之间可能不同的结构体内存布局、不同的大小端机制、不同的指针宽度之间的正确通信,在运行时几乎不会引入任何额外的开销;通过 eBPF Maps 通信的时候数据可以直接由内核态复制到 Wasm 虚拟机的内存中,避免多次拷贝带来的额外损耗。同时,通过自动生成 skeleton (bpf 代码框架)和类型定义的方式,用户态程序的 eBPF-Wasm 开发体验也得到了非常大的改善。


得益于 libbpf 提供的 CO-RE(Compile-Once, Run Everywhere)技术,在不同内核版本之间移植 eBPF 字节码对象,也不需要引入额外的重新编译流程,运行时也没有任何的 LLVM/Clang 依赖[8]。


通常一个编译好的 eBPF-Wasm 模块只有大约 90Kb,在不到 100ms 内即可以完成动态加载进内核并执行的过程。我们也在仓库中提供了几个例子,分别对应于可观测、网络、安全等多种场景。


感谢华南理工大学赖晓铮副教授、西安邮电大学陈莉君教授团队和达坦科技对 Wasm 和 eBPF 相结合的指导与帮助,在接下来的工作中,我们会一同针对一些 Wasm-bpf 具体的应用场景,进行更深入的研究与探讨,并在下一篇 blog 中给出更详细的原理解析与性能分析,以及对应的一些示例代码。


Wasm-bpf 编译工具链与运行时模块等目前由 eunomia-bpf 开源社区开发与维护,感谢中科院软件所 PLCT 实验室对社区的大力支持和资助,感谢社区同伴们的贡献。接下来,也会在对应的 eBPF 和 Wasm 相关的工具链和运行时方面,进行更多的完善和探索,并积极向上游社区反馈和贡献。

参考资料

2023-02-25 11:229452

评论

发布
暂无评论
发现更多内容

斗栱云杜文宝:如何用一款SaaS改变建筑行业?

ToB行业头条

Vue-15-事件绑定

Python研究所

6月月更

Java—指令重排序

武师叔

6月月更

NFT数字藏品APP系统开发

开发微hkkf5566

钱大妈基于 Flink 的实时风控实践

Apache Flink

大数据 flink 编程 流计算 实时计算

轻松实现微信滑动返回页面效果 | 社区征文

Changing Lin

android 安卓 自定义view 初夏征文

封装业务流程,解决复杂重复的审批流程配置

明道云

父亲节特辑丨童年经典蓝精灵之百变蓝爸爸数字藏品,限量发售!

百度开发者中心

8种桌面IDE CodeArts智能代码补全类型

华为云开发者联盟

云计算 代码 华为云

Spring Security:用户和Spring应用之间的安全屏障

华为云开发者联盟

安全 防火墙 spring security 华为云

【CVPR2022】用于域适应语义分割的域无关先验

华为云开发者联盟

人工智能 华为云 图像域

OceanBase Meetup第五期 复杂业务场景下的数据库应用需求及挑战

OceanBase 数据库

Spring那点事

飞天

6月月更

安擎人工智能计算中心解决方案助推“城市大脑”建设

科技热闻

多任务视频推荐方案,百度工程师实战经验分享

百度开发者中心

数商云X日本高化学,共同打造跨境化学品B2B平台新范式

数商云

数字化转型 b2b

并发数、并发以及高并发分别是什么意思?

行云管家

高并发 并发 堡垒机 IT运维 并发数

web前端培训 | 面试中Vue的各种原理分享

@零度

Vue 前端开发

如何保证数据库和缓存双写一致性?

C++后台开发

数据库 redis 缓存 中间件 后端开发

自适应批作业调度器:为 Flink 批作业自动推导并行度

Apache Flink

大数据 flink 编程 流计算 实时计算

游戏源代码开发时需要什么,需要哪些团队成员?

开源直播系统源码

软件开发 游戏开发 直播源码

K8s的负载均衡与配置管理

Damon

云原生 k8s 6月月更

大数据工业界解决方案

Joseph295

去中心化交易所套利机器人开发技术

薇電13242772558

区块链 去中心化

重新认识WorkPlus,不止IM即时通讯,是企业移动应用管理专家

WorkPlus

我的远程办公经验 | 社区征文

坚果

初夏征文

什么是网络拓扑?网络拓扑有哪些类型?

wljslmz

网络技术 6月月更 网络拓扑

fastposter v2.8.3 发布 电商海报生成器

物有本末

Java Python 海报 海报生成

揭开SSL的神秘面纱,了解如何用SSL保护数据

郑州埃文科技

数据安全 SSL证书 IP溯源

云原生多云管理利器 -- cluster-api 之 ControlPlane

Daocloud 道客

Kubernetes 云原生 多云管理 cluster-api ControlPlane

CRM快速开发平台:破解管理困局

力软低代码开发平台

Wasm-bpf: 为云原生 Webassembly 提供通用的 eBPF 内核可编程能力_开源_郑昱笙_InfoQ精选文章