WebAssembly与Rust:WASI的未来

WebAssembly 最初是为浏览器设计的,但 WASI 正在把它带向更广阔的领域。从 Serverless 到边缘计算,从插件系统到通用运行时,Wasm + WASI 的组合正在重新定义"一次编译,到处运行"的含义。

WASI 是什么

WASI,全称 WebAssembly System Interface,是 WebAssembly 在浏览器之外运行时所需的系统接口标准。

WebAssembly 本身是一个纯计算的沙箱——它能做算术运算、操作内存,但不能访问文件系统、网络、时钟等系统资源。在浏览器中,这些能力由 JavaScript 桥接提供。但在浏览器之外(比如服务器上),需要一套标准化的接口来提供这些能力,这就是 WASI 的角色。

WASI 的设计原则是基于能力的安全模型(capability-based security):Wasm 模块默认没有任何系统权限,只有宿主显式授予的能力才可用。比如一个模块想读取 /data 目录,宿主必须在启动时将这个目录的读权限传给它。这和 Linux 的文件描述符传递思路类似,但粒度更细。

WASI Preview 2 与 Component Model

WASI 目前有两个版本在使用:

Preview 1:2020 年发布的初始版本,提供了基本的文件系统、环境变量、命令行参数、随机数等接口。接口设计偏 POSIX 风格,比较底层。目前大多数工具和运行时支持的是这个版本。

Preview 2:2024 年初进入稳定状态的新版本,基于 Component Model 重新设计。这是一个根本性的变化。

Component Model 是 WebAssembly 生态中最重要的在建标准之一。它解决的核心问题是:不同语言编译出的 Wasm 模块如何互相调用。

在 Preview 1 中,Wasm 模块之间只能通过原始的数字类型(i32、i64、f32、f64)交互,传递字符串或复杂结构需要手动做内存布局。Component Model 引入了 WIT(WebAssembly Interface Type)来定义高级别的接口类型,包括字符串、列表、记录(struct)、变体(enum)、结果类型等。

WIT 接口长这样:一个 package 下可以定义多个 interface,每个 interface 包含类型定义和函数签名。一个 world 定义了一个组件的完整接口——它导入什么、导出什么。

这意味着一个 Rust 编写的 Wasm 组件可以被 Python、Go、JavaScript 编写的宿主程序调用,不需要处理 FFI 细节。Component Model 提供了一种类似 gRPC/Protobuf 但在二进制指令层面实现的跨语言互操作方案。

运行时

两个主要的 Wasm 运行时:

Wasmtime:Bytecode Alliance(Mozilla、Fastly、Intel 等发起)维护,Rust 实现。是 WASI 标准的参考实现,对 Preview 2 和 Component Model 的支持最完整。性能上使用 Cranelift 作为 JIT 后端,启动速度快,适合 Serverless 场景。

Wasmer:商业公司 Wasmer Inc 维护。提供了更丰富的部署选项,包括自己的包管理器(wapm)和边缘部署平台(Wasmer Edge)。支持多个编译后端(Cranelift、LLVM、Singlepass),其中 Singlepass 是单遍编译器,启动速度极快,适合对冷启动敏感的场景。

还有一些专注特定领域的运行时:WasmEdge 面向边缘计算和 AI 推理,Spin(Fermyon)面向 Serverless 微服务。

Rust 与 WASI 的关系

Rust 是编译到 Wasm/WASI 最成熟的语言,有几个原因:

  • 没有垃圾回收器,不需要在 Wasm 中嵌入 GC runtime
  • 编译产物小,一个简单程序编译出的 wasm 文件通常在几百 KB
  • 标准库对 wasm32-wasip1wasm32-wasip2 target 有官方支持
  • cargo-component 工具可以直接编译出 Component Model 格式的组件

Rust 编译到 WASI 的工具链已经很成熟:添加 target、使用 cargo build 指定 target 即可编译,wasmtime 可以直接运行编译产物。

应用场景

Serverless / FaaS:这是 Wasm 最被看好的服务端场景。相比容器,Wasm 的优势是启动速度快(微秒级 vs 秒级)和资源占用小。Cloudflare Workers、Fastly Compute、Fermyon Cloud 都在用 Wasm 作为 Serverless 运行时。

边缘计算:CDN 节点上运行 Wasm 模块处理请求,比如 A/B 测试、请求改写、身份验证。Fastly 和 Cloudflare 的边缘计算平台就是基于 Wasm。

插件系统:这可能是最实际的近期应用场景。很多应用需要插件/扩展能力,传统方案要么用脚本语言(Lua、Python),要么用动态链接库。Wasm 提供了一个沙箱化的、跨语言的插件运行环境。

已有的案例:Envoy 代理的 Wasm Filter、Figma 的插件系统、Zed 编辑器的扩展系统。这些场景的共同特点是需要运行不受信任的第三方代码,Wasm 的沙箱隔离特性恰好满足需求。

通用容器替代:Docker 创始人 Solomon Hykes 的那句话:"如果 2008 年就有 WASM + WASI,我们就不需要 Docker 了。"虽然有些夸张,但反映了一种趋势——对于不需要完整 OS 环境的工作负载,Wasm 是比容器更轻量的选择。

当前限制

WASI 还有不少短板:

  • 网络支持:WASI Preview 2 才刚开始标准化 TCP/UDP 接口(wasi:sockets),HTTP 也是(wasi:http)。很多网络相关的 crate 还不能直接编译到 WASI
  • 线程:wasi-threads 提案还在早期,目前大多数场景是单线程
  • 生态成熟度:很多 Rust crate 依赖了系统调用(比如 tokio 依赖 epoll/kqueue),不能直接编译到 WASI
  • 调试:Wasm 的调试工具还不够好,出了问题排查成本较高

展望

WASI 的路线图很清晰:Preview 2 已经稳定,社区正在推进更多子提案(键值存储、消息队列、AI 推理接口等)。Component Model 的成熟将使跨语言组件化成为现实。

对于 Rust 开发者来说,现在就可以开始关注 WASI:在插件系统和 Serverless 两个方向上,Wasm + Rust 的组合已经具备生产可用性。