mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
2156 字
6 分钟
eBPF 与 WebAssembly
2026-03-11

eBPF 和 WebAssembly 是近年来最热门的两种”可编程”技术——eBPF 让内核可编程,Wasm 让应用可移植。它们看似属于不同领域,但融合后产生了令人兴奋的化学反应:Wasm-eBPF 让 eBPF 程序可以像 Wasm 模块一样打包、分发和运行,实现了”一次编写,到处运行”的终极可移植性。

本章探索 eBPF 与 WebAssembly 的融合,理解 Wasm-eBPF 的架构、用户态 eBPF 运行时,以及这一融合在边缘计算、插件系统中的应用前景。

一、eBPF 与 Wasm 的互补性#

1.1 各自的优势#

维度eBPFWebAssembly
运行位置内核态用户态
安全模型验证器沙箱
可移植性CO-RE(Linux 内核间)跨平台(OS/架构)
性能接近原生接近原生
生态Linux 内核浏览器 + 服务器
语言支持C/Rust(受限)C/Rust/Go/AssemblyScript 等
灵活性受验证器限制完全图灵完备

1.2 融合的动机#

flowchart TB subgraph eBPF优势["eBPF 优势"] E1["内核级可观测性"] E2["高性能网络处理"] E3["安全策略执行"] end subgraph Wasm优势["Wasm 优势"] W1["跨平台可移植性"] W2["丰富的语言支持"] W3["沙箱隔离"] W4["轻量级插件系统"] end eBPF优势 -->|"融合"| FUSION["Wasm-eBPF<br/>内核能力 + 跨平台"] Wasm优势 -->|"融合"| FUSION style FUSION fill:#c8e6c9,stroke:#2e7d32

融合的核心动机:

  1. 跨平台可移植性:eBPF 程序只能在 Linux 内核上运行,Wasm-eBPF 让它在 macOS、Windows 上也能运行(通过用户态运行时)
  2. 插件化分发:eBPF 程序可以作为 Wasm 插件打包和分发
  3. 安全隔离:Wasm 沙箱为 eBPF 用户态组件提供额外隔离
  4. 语言多样性:Wasm 支持更多语言编写 eBPF 用户态逻辑

二、Wasm-eBPF 项目#

2.1 架构#

Wasm-eBPF 是由 eunomia-bpf 项目发起的开源项目,将 eBPF 程序打包为 Wasm 模块:

flowchart TB subgraph 开发阶段 BPF_C["eBPF C 程序<br/>hello.bpf.c"] -->|"clang 编译"| BPF_O["hello.bpf.o"] APP_WASM["Wasm 用户态<br/>app.rs / app.c"] -->|"编译为 Wasm"| APP_WASM_O["app.wasm"] BPF_O -->|"打包"| BUNDLE["eBPF-Wasm Bundle"] APP_WASM_O -->|"打包"| BUNDLE end subgraph 运行阶段 BUNDLE -->|"Wasm 运行时"| RUNTIME["eBPF-Wasm 运行时"] RUNTIME -->|"加载 eBPF 字节码"| LOADER["用户态 eBPF 加载器"] LOADER -->|"bpf() 系统调用"| KERNEL["Linux 内核"] RUNTIME -->|"执行 Wasm 逻辑"| WASM_RT["Wasm 沙箱"] WASM_RT <-->|"读写 Map"| LOADER end style BUNDLE fill:#c8e6c9,stroke:#2e7d32 style RUNTIME fill:#bbdefb,stroke:#1565c0

2.2 Wasm-eBPF 的工作流程#

  1. 开发:编写 eBPF 内核态程序(C)和 Wasm 用户态逻辑(Rust/C)
  2. 编译:eBPF 程序编译为字节码,用户态逻辑编译为 Wasm
  3. 打包:将 eBPF 字节码和 Wasm 模块打包为一个 Bundle
  4. 分发:Bundle 可以像普通 Wasm 模块一样分发
  5. 运行:Wasm-eBPF 运行时加载 Bundle,执行 eBPF 程序

2.3 eBPF 程序示例#

// eBPF 程序(与普通 eBPF 程序相同)
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
struct event {
u32 pid;
char comm[16];
};
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} events SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_execve")
int trace_execve(struct trace_event_raw_sys_enter *ctx)
{
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
e->pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
bpf_ringbuf_submit(e, 0);
return 0;
}
char LICENSE[] SEC("license") = "GPL";

2.4 Wasm-eBPF SDK 详解#

Wasm-eBPF 提供了多语言 SDK,让开发者可以用 Go、Rust 等语言编写用户态逻辑,通过 SDK 操作 eBPF Map 和处理事件。

Go SDK 示例

package main
import (
"fmt"
"github.com/eunomia-bpf/wasm-eBPF/sdk/go"
)
func main() {
// 初始化 eBPF-Wasm 运行时
runtime := ewasm.NewRuntime()
defer runtime.Close()
// 加载 eBPF 程序
if err := runtime.LoadBpfObject("hello.bpf.o"); err != nil {
panic(err)
}
// 附加到 tracepoint
if err := runtime.Attach("tracepoint/syscalls/sys_enter_execve"); err != nil {
panic(err)
}
// 获取 Map 操作句柄
events := runtime.GetRingBuf("events")
fmt.Println("PID COMM")
for {
event, err := events.Read()
if err != nil {
continue
}
fmt.Printf("%-8d%s\n", event.Pid, event.Comm)
}
}

Map 操作 API

操作Go SDK 方法说明
查找map.Lookup(&key, &value)按 key 查找 value
更新map.Update(&key, &value, flags)插入或更新条目
删除map.Delete(&key)删除条目
遍历map.Iterate()遍历所有条目
Ring Buffer 读取ringbuf.Read()读取事件
Per-CPU 查找map.LookupPerCpu(&key)读取 Per-CPU Map

错误处理模式

// Go SDK 的错误处理
value, err := map.Lookup(&key)
if err != nil {
if errors.Is(err, ewasm.ErrKeyNotFound) {
// key 不存在,创建新条目
newValue := &Event{Count: 1}
if err := map.Update(&key, newValue, ewasm.UpdateAny); err != nil {
log.Printf("update failed: %v", err)
}
} else {
log.Printf("lookup failed: %v", err)
}
}

2.5 WASI 与 eBPF 集成#

WebAssembly System Interface(WASI)是 Wasm 的系统接口标准,eBPF 社区正在推动通过 WASI 将 eBPF 能力标准化暴露给 Wasm 模块:

flowchart TB subgraph Wasm模块["Wasm 模块"] APP["应用逻辑"] end subgraph WASI层["WASI 扩展层"] WASI_STD["WASI 标准<br/>文件/网络/时钟"] WASI_BPF["WASI-bpf 扩展<br/>eBPF 操作"] end subgraph 运行时["运行时实现"] WASM_RT["Wasm 运行时<br/>Wasmtime/Wasmer"] BPF_LOADER["eBPF 加载器"] end APP -->|"标准调用"| WASI_STD APP -->|"eBPF 调用"| WASI_BPF WASI_STD --> WASM_RT WASI_BPF --> BPF_LOADER BPF_LOADER -->|"bpf()"| KERNEL["Linux 内核"] style WASI_BPF fill:#c8e6c9,stroke:#2e7d32

WASI-bpf 提案定义了以下接口:

接口说明状态
bpf_prog_load()加载 eBPF 程序草案
bpf_map_operate()Map 增删改查草案
bpf_attach()附加到 Hook 点草案
bpf_ringbuf_read()读取 Ring Buffer草案

WASI Component Model 进一步将 eBPF 能力封装为可组合的组件——不同语言的 Wasm 模块可以通过标准接口共享 eBPF Map 和事件流,实现真正的跨语言协作。

三、用户态 eBPF 运行时#

3.1 为什么需要用户态运行时#

eBPF 程序只能在 Linux 内核上运行,但开发者可能在 macOS 或 Windows 上开发。用户态 eBPF 运行时提供了在非 Linux 系统上运行 eBPF 程序的能力:

运行时支持平台实现方式
bpftimeLinux/macOS用户态 JIT + Uprobe
ubpf任意纯解释器
Wasm-eBPF任意(Wasm 运行时)Wasm 沙箱 + 系统调用转发

3.2 bpftime:高性能用户态运行时#

bpftime 是一个高性能的用户态 eBPF 运行时,支持 uprobe 和用户态 Hook:

flowchart TB APP["用户态应用"] -->|"uprobe"| BPFTIME["bpftime 运行时"] BPFTIME -->|"JIT 编译"| NATIVE["本机码执行"] BPFTIME -->|"Map 操作"| MAP["用户态 Map<br/>共享内存"] style BPFTIME fill:#c8e6c9,stroke:#2e7d32

3.3 bpftime 的执行模式#

bpftime 支持两种执行模式,在性能和兼容性之间提供选择:

// JIT 模式:将 eBPF 字节码编译为本机码
// 性能接近内核 eBPF,但需要运行时生成代码权限
bpftime -j hello.bpf.o
// 解释器模式:逐条解释执行 eBPF 字节码
// 性能较低,但兼容性更好,可在受限环境中运行
bpftime -i hello.bpf.o
flowchart LR subgraph JIT模式["JIT 模式"] BPF_O1["eBPF 字节码"] -->|"LLVM JIT"| NATIVE1["本机码<br/>~95% 原生性能"] end subgraph 解释器模式["解释器模式"] BPF_O2["eBPF 字节码"] -->|"逐条解释"| INTERP["解释执行<br/>~30% 原生性能"] end style JIT模式 fill:#c8e6c9,stroke:#2e7d32 style 解释器模式 fill:#fff9c4,stroke:#f9a825
模式性能兼容性适用场景
JIT~95% 原生需要 JIT 权限生产环境、高频 Hook
解释器~30% 原生任意环境开发调试、受限环境

3.4 性能基准测试#

Wasm-eBPF、原生 eBPF 和 bpftime 在不同 Hook 类型下的性能对比:

Hook 类型原生 eBPFWasm-eBPFbpftime (JIT)bpftime (解释)
uprobe(单次)~1.5μs~2.0μs~1.8μs~5.0μs
tracepoint~0.8μsN/A~1.0μs~3.5μs
Map 查找(Hash)~100ns~200ns~150ns~400ns
Map 更新(Hash)~200ns~350ns~250ns~600ns
Ring Buffer 写入~50ns~120ns~80ns~200ns
# 运行 bpftime 基准测试
bpftime benchmark --type uprobe --iterations 100000
# 运行 Wasm-eBPF 基准测试
ewasm benchmark --type uprobe --iterations 100000
Note

Wasm-eBPF 的额外开销主要来自 Wasm 沙箱的上下文切换和 Map 操作的跨边界调用。对于 uprobe 场景,Wasm-eBPF 的开销约 30%,在可接受范围内。但对于 XDP 等纳秒级敏感场景,目前仍需使用原生 eBPF。

3.5 用户态运行时的限制#

限制说明
仅支持用户态 Hook无法追踪内核函数
Map 实现不同用户态 Map 基于共享内存
不支持 XDP/TC这些需要内核支持
性能差异用户态运行时性能低于内核
Helper 函数有限仅支持用户态可实现的 Helper
Warning

用户态 eBPF 运行时不是内核 eBPF 的替代品,而是开发辅助工具——让你在非 Linux 系统上开发和测试 eBPF 程序,最终仍需在 Linux 内核上运行。

四、eBPF + Wasm 的应用场景#

4.1 边缘计算#

flowchart TB subgraph 边缘节点["边缘节点(轻量级)"] WASM_RT["Wasm 运行时"] EBPF_BUNDLE["eBPF-Wasm Bundle<br/>网络监控 + 安全策略"] end subgraph 云端["云端控制面"] POLICY["策略引擎"] REGISTRY["Wasm Registry<br/>插件仓库"] end 云端 -->|"下发策略"| 边缘节点 REGISTRY -->|"拉取插件"| 边缘节点 EBPF_BUNDLE --> WASM_RT style 边缘节点 fill:#c8e6c9,stroke:#2e7d32 style 云端 fill:#bbdefb,stroke:#1565c0

边缘计算场景的优势:

  1. 轻量级:Wasm 运行时比容器更轻量,适合资源受限的边缘设备
  2. 热更新:Wasm 插件可以动态加载和替换,无需重启
  3. 安全隔离:Wasm 沙箱防止恶意插件影响系统
  4. 跨平台:同一插件可以在不同架构的边缘设备上运行

4.2 可观测性插件系统#

flowchart TB subgraph 可观测性平台["可观测性平台"] AGENT["Agent<br/>Wasm 运行时"] P1["插件 1<br/>进程监控"] P2["插件 2<br/>网络追踪"] P3["插件 3<br/>I/O 分析"] end AGENT --> P1 AGENT --> P2 AGENT --> P3 P1 -->|"eBPF 事件"| EXPORTER["Exporter"] P2 --> EXPORTER P3 --> EXPORTER EXPORTER --> BACKEND["后端<br/>Prometheus/Grafana"] style AGENT fill:#c8e6c9,stroke:#2e7d32 style P1 fill:#bbdefb,stroke:#1565c0 style P2 fill:#bbdefb,stroke:#1565c0 style P3 fill:#bbdefb,stroke:#1565c0

4.3 跨平台开发与测试#

Wasm-eBPF 让开发者可以在 macOS/Windows 上开发和测试 eBPF 程序:

# 在 macOS 上开发 eBPF 程序
# 使用 Wasm-eBPF 运行时测试
ewasm run my-ebpf-app.wasm
# 部署到 Linux 生产环境
# Wasm 运行时自动切换为内核 eBPF 加载

五、调试 Wasm-eBPF 程序#

5.1 双重世界调试#

Wasm-eBPF 程序横跨两个执行环境——eBPF 内核态和 Wasm 用户态,调试时需要分别处理:

# 调试 eBPF 内核态部分
sudo bpftool prog show # 查看已加载的 eBPF 程序
sudo bpftool map show # 查看 Map 状态
sudo cat /sys/kernel/debug/tracing/trace_pipe # 查看 bpf_trace_printk 输出
# 调试 Wasm 用户态部分
WASM_DEBUG=1 ewasm run my-app.wasm # 启用 Wasm 调试日志

5.2 常见调试技巧#

# 1. 验证 eBPF 程序是否加载成功
sudo bpftool prog list | grep trace_execve
# 如果没有输出,检查验证器日志:
sudo dmesg | grep bpf
# 2. 检查 Map 数据是否正确
sudo bpftool map dump name events
# 如果 Map 为空,检查 eBPF 程序的 attach 状态
# 3. 追踪 Wasm-eBPF 运行时内部行为
EWASM_LOG=debug ewasm run my-app.wasm 2>&1 | head -50
# 4. 对比原生 eBPF 和 Wasm-eBPF 的输出
# 先用 bpftool 运行原生版本
sudo bpftool prog load hello.bpf.o /sys/fs/bpf/hello type tracepoint
# 再用 Wasm-eBPF 运行,对比结果
Tip

调试 Wasm-eBPF 程序时,先确保 eBPF 内核态部分独立运行正常,再排查 Wasm 用户态逻辑。可以先用 bpftoolbpftrace 单独测试 eBPF 程序,确认内核态无误后再集成到 Wasm 模块中。

六、eBPF + Wasm 的挑战#

6.1 技术挑战#

挑战说明当前状态
性能开销Wasm 沙箱增加间接层可接受(<10%)
内核功能缺失用户态运行时无法支持 XDP/TC仅支持 uprobe/tracepoint
调试困难Wasm + eBPF 双重调试工具链不成熟
标准化eBPF-Wasm 接口未标准化社区讨论中
生态不成熟Wasm-eBPF 项目较少快速发展中

6.2 未来展望#

timeline title eBPF + Wasm 发展路线 2023 : Wasm-eBPF 概念验证 : eunomia-bpf 项目启动 2024 : bpftime 用户态运行时 : Wasm-eBPF v0.1 发布 2025 : 边缘计算场景落地 : 可观测性插件系统 2026 : 标准化接口 : 更多语言支持 : 生产级部署

七、生产案例:可观测性插件平台#

7.1 场景#

某云厂商的可观测性平台需要支持第三方开发者编写自定义监控插件。传统方案基于 gRPC 插件,存在启动慢、资源占用高、安全隔离弱等问题。团队采用 Wasm-eBPF 方案重构插件系统。

7.2 架构#

flowchart TB subgraph 插件平台["可观测性插件平台"] AGENT["Agent<br/>Wasm 运行时 + eBPF 加载器"] P1["进程监控插件<br/>Wasm-eBPF"] P2["网络追踪插件<br/>Wasm-eBPF"] P3["自定义插件<br/>用户上传"] end subgraph 基础设施["基础设施"] REGISTRY["插件仓库<br/>OCI Registry"] CONTROL["控制面<br/>策略下发"] end REGISTRY -->|"拉取插件"| AGENT CONTROL -->|"下发配置"| AGENT AGENT --> P1 AGENT --> P2 AGENT --> P3 P1 -->|"Metrics"| EXPORTER["Exporter<br/>Prometheus"] P2 --> EXPORTER P3 --> EXPORTER style AGENT fill:#c8e6c9,stroke:#2e7d32 style P3 fill:#fff9c4,stroke:#f9a825

7.3 关键实现#

插件以 Wasm-eBPF Bundle 形式分发,Agent 负责加载和调度:

  1. eBPF 内核态:每个插件包含独立的 eBPF 程序,采集特定指标
  2. Wasm 用户态:处理事件、聚合指标、输出 Prometheus Metrics
  3. 资源隔离:每个 Wasm 插件有独立的内存和 CPU 限额
  4. 热加载:新插件上传到 OCI Registry 后,Agent 自动拉取并加载,无需重启
Warning

生产环境中,Wasm-eBPF 插件的 eBPF 程序需要 CAP_BPF 权限才能加载到内核。建议将 Agent 运行在特权 DaemonSet 中,而非应用 Pod 内,避免权限泄露。

八、动手实践#

8.1 使用 eunomia-bpf 开发 Wasm-eBPF 程序#

# 安装 eunomia-bpf 工具
wget https://github.com/eunomia-bpf/eunomia-bpf/releases/latest/download/ecc
chmod +x ecc
# 编译 eBPF 程序为 Wasm Bundle
./ecc hello.bpf.c
# 运行
ecli run hello.bpf.o

8.2 使用 bpftime 在用户态运行 eBPF#

# 安装 bpftime
curl -fsSL https://github.com/eunomia-bpf/bpftime/releases/latest/download/install.sh | bash
# 使用 bpftime 运行 eBPF 程序
bpftime load hello.bpf.o
# 查看输出
bpftime trace

8.3 开发 Wasm 插件#

# 使用 eunomia-bpf 模板创建项目
ecc init my-plugin --template wasm
# 编写 eBPF 程序和 Wasm 用户态逻辑
cd my-plugin
# 编辑 hello.bpf.c 和 app.rs
# 编译
make
# 运行
ecli run bundle.json

九、本章小结#

上一章探讨了eBPF 开发框架。 本章探索了 eBPF 与 WebAssembly 的融合:

主题核心要点关键词
互补性eBPF 提供内核能力,Wasm 提供跨平台可移植性互补性
Wasm-eBPF将 eBPF 程序打包为 Wasm 模块,实现跨平台分发Wasm-eBPF
用户态运行时bpftime 等项目让 eBPF 程序在非 Linux 系统上运行用户态运行时
应用场景边缘计算、可观测性插件系统、跨平台开发应用场景
挑战性能开销、内核功能缺失、生态不成熟挑战

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

eBPF 与 WebAssembly
https://blog.souloss.com/posts/ebpf/ebpf-and-wasm/
作者
Souloss
发布于
2026-03-11
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

相关文章 智能推荐
1
eBPF 与内存管理
eBPF eBPF 程序的内存使用是生产部署中的关键考量——Map 占用多少内存?eBPF 程序的栈空间有多大?容器环境中的 eBPF 内存如何计费?本章详解 eBPF 的内存模型、Map 内存开销计算、容器内存追踪、eBPF-mm 子系统,以及内存限制下的优化策略。
2
TC:流量控制与 eBPF
eBPF TC(Traffic Control)是 Linux 内核的流量控制子系统,通过 cls_bpf 分类器可以在 TC 层挂载 eBPF 程序,实现灵活的数据包分类、修改和重定向。本章详解 TC eBPF 的架构、ingress/egress 双向处理、direct action 模式、sk_buff 操作,以及 TC 与 XDP 的选择策略。
3
eBPF 可观测性
eBPF eBPF 最大的应用场景是可观测性——零侵入、低开销、内核级的全链路追踪。本章详解三大可观测性工具链——bpftrace(一行命令追踪内核)、BCC(Python 前端 + 丰富工具集)、Beyla(零侵入应用性能监控),并通过实战展示性能分析、分布式追踪、应用性能监控的完整工作流。
4
eBPF 网络全景
eBPF eBPF 正在重新定义 Linux 网络栈——从连接跟踪、NAT 到 kube-proxy 替代,从 Socket Filter 到 Sk_msg 重定向,eBPF 提供了比 iptables/netfilter 更高性能、更灵活的网络方案。本章从宏观视角展示 eBPF 网络的全景,详解连接跟踪、NAT、kube-proxy 替代、Socket 层 eBPF,并对比 eBPF 与传统网络方案的架构差异。
5
eBPF Hook 点:kprobe/tracepoint/uprobe
eBPF eBPF 程序的价值在于它能挂载到内核的各种检查点——Hook 点。本章详解三大 Hook 机制——kprobe(动态内核函数追踪)、tracepoint(静态追踪点)、uprobe(用户态函数追踪),以及 USDT 静态用户态追踪点,并通过实战代码展示每种 Hook 的使用方式与适用场景。