Podman 运行时大比拼:Native vs Wasm(Edge) vs libkrun
随着容器技术的不断演进,Podman 已经不仅仅是一个运行 Docker 容器的工具。通过 crun 运行时的扩展,Podman 现在支持直接运行 WebAssembly (Wasm) 工作负载以及基于 KVM 隔离的 libkrun 虚拟机。
最近,Red Hat 的软件工程师 Jose Castillo Lema 发布了一篇非常有价值的评测文章,对比了 Native Linux 容器、Wasm (通过 WasmEdge) 以及 libkrun 在 Podman 下的性能表现。本文将对这篇评测进行深度总结和解读,带你了解这三种运行时的优劣与适用场景。
1. 三种运行时简介
在深入评测数据之前,我们先简要了解一下这三位参赛选手:
1.1 Native Podman (Linux Containers)
这是我们最熟悉的传统容器模式。利用 Linux 内核的 Namespace 和 Cgroups 特性,实现进程级别的隔离。
- 特点:性能接近裸机,资源开销极低,生态最成熟。
1.2 WebAssembly (Wasm)
Wasm 最初是为浏览器设计的二进制指令格式,现在已经扩展到了服务端。Podman 通过集成 crun 和 Wasm 运行时(如 WasmEdge, Wasmtime, Wasmer)来支持 Wasm 容器。
- 特点:极强的可移植性(一次编译,到处运行),沙箱安全,极快的启动速度。本评测使用的是 WasmEdge 运行时。
1.3 libkrun
libkrun 是一个动态库,允许程序使用 Linux 上的 KVM 或 macOS 上的 HVF 来运行部分隔离的进程。实际上,它是在启动一个极其轻量级的虚拟机(microVM)。
- 特点:提供虚拟机级别的隔离(比传统容器更安全),专为机密计算(Confidential Workloads)设计,启动速度快于传统 VM 但慢于容器。
2. 评测环境与方法
为了公平对比,作者使用了一个简单的 Rust HTTP Server 作为基准测试程序。
- 测试工具:Drill (也是 Rust 编写的 HTTP 压测工具)
- 负载类型:混合 HTTP GET 和 POST 请求
- 测试场景:
- Native:编译为
x86_64-unknown-linux-musl的二进制文件。 - Wasm:编译为
wasm32-wasi的二进制文件,通过 WasmEdge 运行。 - libkrun:使用
run.oci.handler=krun标注运行。
- Native:编译为
3. 评测结果:全方位对比
3.1 镜像大小 (Image Size)
在云原生时代,镜像分发速度至关重要,而镜像大小直接影响分发效率。
- Wasm 获胜:Wasm 镜像仅 1.17 MB,比 Native 镜像(4.93 MB)小了 77%。
- 原因:Wasm 字节码非常紧凑,且不需要包含操作系统层面的库文件(Native 镜像使用了 musl 以保持最小化,但仍比 Wasm 大)。
3.2 资源消耗 (Resource Usage)
我们来看看在空闲(Idle)和负载(Under Load)状态下的 CPU 和内存表现。
空闲状态 (Idle)
| 运行时 | CPU 使用率 | 内存使用 (MB) | 备注 |
|---|---|---|---|
| Native | 0.01% | 0.2 | 几乎可以忽略不计 |
| WasmEdge | 0.04% | 26.35 | 内存占用虽小但比 Native 高 |
| libkrun | 3.15% | 101.5 | 虚拟化带来的额外开销 |
负载状态 (Under Load)
- CPU: Native 占用约 0.5 个核心;WasmEdge 占用约 1 个核心;libkrun 占用超过 2.5 个核心。
- 内存: 负载下内存增长不明显,Native 依然最低,libkrun 维持在 100MB 左右。
分析:libkrun 由于涉及虚拟化层,CPU 和内存开销显著高于其他两者。WasmEdge 在 CPU 效率上不如 Native 代码高效,这符合预期,因为 Wasm 运行时需要进行 JIT 编译或解释执行。
3.3 网络性能 (Networking Performance)
这是本次评测差异最巨大的部分,也是决定生产环境选型的关键指标。
测试指标为 RPS (Requests Per Second),即每秒处理请求数。
- Native: ~65,000 RPS。基准线,性能最强。
- libkrun: ~45,000 RPS。表现亮眼,达到了 Native 的 70% 左右。这得益于它使用的
virtio-vsock+TSI机制,透明地替换了 socket 通信,既高效又无需改动应用代码。 - WasmEdge: ~2,600 RPS。仅为 Native 的 4%!而且在高负载下容易失去响应。
Wasm 网络性能之谜:为了确认是否是 Podman 集成导致的问题,作者脱离 Podman 直接运行 WasmEdge CLI 进行测试,结果 RPS 约为 2,188,甚至还没 Podman 容器内快(Podman 内测试可能有波动,但量级一致)。这说明瓶颈在 WasmEdge 运行时 或其网络栈实现(
hyper_wasi,tokio_wasi)上。
通过 FlameGraph 分析,大部分时间消耗在了 libwasmedge.so 的调用上。虽然 Wasm 在计算密集型任务上已接近 Native 性能,但在网络 I/O 密集型任务上,目前的生态栈仍有巨大的优化空间。
4. 总结与选型建议
根据 Jose Castillo Lema 的评测结果,我们可以得出以下结论:
通用首选:Native Containers
- 如果你没有特殊需求,标准的 Linux 容器依然是性能最好、资源最省、最成熟的选择。
隔离与安全:libkrun
- 如果你需要比 Namespace 更强的隔离性(例如多租户环境、运行不可信代码),
libkrun是一个极佳的选择。 - 它在提供 VM 级隔离的同时,保持了相当不错的网络性能(Native 的 70%),远超用户空间模拟的传统方案。
- 如果你需要比 Namespace 更强的隔离性(例如多租户环境、运行不可信代码),
边缘与轻量:Wasm
- 优势:镜像极小,冷启动极快,跨平台。
- 劣势:网络 I/O 性能目前较差(仅为 Native 的 4%),且在高并发下不稳定。
- 适用场景:适合计算密集型的任务(如图像处理、AI 推理)、Serverless 函数(冷启动要求高)、或者网络流量不大的边缘计算场景。不建议用于高吞吐量的 Web 服务。
展望
WebAssembly 的生态正在飞速发展。虽然目前的网络性能测试结果不尽如人意,但随着 WASI (WebAssembly System Interface) 标准的完善(特别是 WASI-preview2 对 socket 的原生支持)以及运行时(Runtime)的优化,未来 Wasm 在服务端的表现值得期待。
参考文章:Playing with Podman crun backends: Wasm(Edge) and libkrun - GitOps