比原生更快:在 Linux 内核中运行 WebAssembly

过去的几个月间,我们尝试了各种方法来给 Wasmer WebAssembly 运行环境提速。这些方法包括缓存编译后的代码、实现不同等级的编译后端(Singlepass/Cranelift/LLVM)等,也都取得了不错的效果。

这些优化性能的尝试使我们开始考虑一个更加“基础”的问题:基于 VM(虚拟机)的程序与原生程序相比,有哪些优势?我们是否可以让 WASM 运行得比原生代码更快?

这篇文章将介绍我们在 Linux 内核中实现的 WebAssembly 安全运行环境。我们在 Linux 内核中成功运行了一个 TCP Echo 服务端程序,并取得了相对原生代码 10% 的性能提升。

背景

  • “第二个操作系统“

许多语言和运行环境,包括 WebAssembly(支持 WASI 的实现)和 JavaScript (Node.js 和浏览器)等,都在尝试于真实的操作系统之上构建第二个沙箱化的“操作系统”。然而,这多出来的一层会带来不小的性能损耗。

640?wx_fmt=png

如上图所示,在这样的传统架构中,来自 VM 上应用的系统服务请求(系统调用),在到达内核前,需要经过两层边界。

这两层边界的性能损耗很大。一个普通的函数调用所需时间一般小于 5 ns,然而一次来源于 VM 内部的系统调用可能会消耗上百纳秒。

  • Cervus 的后继者

我大约一年之前写过另一个内核中的 WebAssembly “用户模式”子系统 - Cervus 。那时候 WASI 和“生产级别”的 WebAssembly 运行时都还不存在,但 Cervus 项目已经证明这个想法是可行且有巨大潜力的。

现在 WebAssembly 生态正在快速成长,是时候做一个完整的、面向真实应用的内核模式 WebAssembly 运行环境了。

为什么要在内核中运行 WebAssembly ?

主要原因是性能和灵活性。

WASM 是由虚拟机保护的虚拟指令集。我们不需要依靠外部的软件/硬件保护来确保安全性。

在内核中运行 WASM 避免了这些外部保护引入的性能损耗,如系统调用(上下文切换)、用户态/内核态数据复制等。

640?wx_fmt=png

同时,有了对底层的控制,我们可以实现很多在用户模式中低效或难以实现的特性,例如直接访问硬件、处理密集的内核事件(如网络包过滤)等。


安全性


在内核模式运行用户代码是件危险的事情。虽然我们用了很多技巧来保护系统免受恶意代码的攻击,我们仍然建议短期之内,在我们没有完整 Review 运行环境代码前,只通过这个模块执行可信的代码。


这里是一些已知的安全风险和我们的应对措施:

  • 栈溢出:在代码生成环节插入边界检查代码

  • 内存访问越界:为每个 WASM 任务分配 6GB 的虚拟地址空间,使越界访问无法表达。

  • 信号无法终止处于内核态的进程:接收到终止信号后,将 WASM 代码页面设置为禁止执行(NX)以强制终止执行。

  • 内核态进程浮点状态丢失:用 kernel_fpu_{begin,end} 与 preempt_notifier 手动保存和恢复浮点状态。

  • 内核不支持 Red Zone :在代码生成器中避免使用之。

例子和性能测试

我们提供了两个例子:echo-server 和 http-server 。它们位于 Wasmer 主仓库的 examples 目录下。

当使用 singlepass 后端编译(无优化直接生成 x86-64 代码),并在本地使用 tcpkali/wrk 测试时,echo-server 比它的用户模式等价实现快约 10% (25210 Mbps / 22820 Mbps) ,http-server 快约 6% (53293 Rps / 50083 Rps) 。

这两个例子使用了 WASI (文件抽象、控制台输出)和我们的异步网络扩展(通过 kernel-net 库)。

可以阅读这两个例子的代码,学习怎样编写在 kernel-wasm 中运行的高性能网络程序。

编译、运行

加载内核模块前,请确保:

  • 你的内核版本大于等于 4.15

  • 你的内核启用了抢占执行(preemption)。尝试在未启用抢占的内核上执行 WASM 用户代码会锁死你的系统。

  • 内核头文件和构建环境已安装

首先,clone 仓库:https://github.com/wasmerio/kernel-wasm

然后在仓库的根目录和 networking 、 wasi 目录下执行 make :

make	
cd networking && make	
cd ../wasi && make	
cd ..

加载模块:

sudo insmod kernel-wasm.ko	
sudo insmod wasi/kwasm-wasi.ko	
sudo insmod networking/kwasm-networking.ko

运行 Wasmer 时选择 singlepass 后端和 kernel 加载器:


 

 

640?wx_fmt=gif

(在 kernel-wasm 上运行的 cowsay )

  • 4
    点赞
  • 1
    收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 1
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值