WebAssembly 是什么?

WebAssembly 简称 WASM,从字面上看,它是由 Web 和 Assembly 组成,可以理解为网络/浏览器汇编,这也表明这项技术的由来,即运行在浏览器内的汇编代码。但是,随着技术的迭代,WebAssembly 早已不局限于它最初的设计愿景。

  1. WebAssembly 不完全是汇编语言,而是一种类似汇编字节码的指令格式标准,由 W3C 的 WASM 工作组ByteCode Aliance(字节码联盟)共同维护。它更像 LLVM-IR 那种比汇编语言更高一些抽象的中间语言,开发者不需要手写 WASM,而是选择使用其他高级语言(如 C、C++、Rust、Go、Python等)编写并编译为 WASM。
  2. WebAssembly 已经不只局限于运行在浏览器上面,如今随着 WASM 生态圈的不断扩展,涌现出了各种与 WASM 兼容的运行时,这些运行时的出现使得 WASM 可以运行在浏览器之外的客户端与服务器端这样的沙盒环境中。

为什么需要 WebAssembly ?

不管是在浏览器还是 Node.js 这样的服务端中,JavaScript 都可以胜任,为什么还需要 WASM ?

主要是因为 JavaScript 的性能问题,本质上,JavaScript 没有静态的变量类型,导致执行引擎所做的编译优化(JIT Compiler)很可能失效。举个例子,JavaScript 代码中定义了一个函数并且包含一个局部变量,开始是它被赋予 Array 类型的值,执行到下一行代码时它又被赋予 Object 类型的值,JIT 编译器所做的优化也就失效了。也正是因为 JavaScript 本身的设计缺陷,导致这门编程语言的发展史变成了填坑史,即使是围绕 JavaScript 的开发生态越来越庞大,它在面对大型复杂项目是还是有点儿捉襟见肘。

当然,开发者为了解决 JavaScript 的性能问题也做了各种尝试,除了 WASM 还有一种优化 JavaScript 的优化子集:asm.js。与 WASM 一样,asm.js 也是一种编译目标,可读性比 WebAssembly 好,但是开发者必须强制使用静态类型,这导致并不是所有的开发者都能够接受;其次 acm.js 的代码还是需要经过“获取-解析-编译-优化”这些耗时的过程,而 WASM 则不用这些步骤,WASM 已经是原生的字节码,而且 WASM 也是静态类型的,这使得大多数优化在其初始编译时就已完成,所以 WebAssembly 比 asm.js 与 原生 JavaScript 快很多。

WebAssembly 的特性

WASM 有几个关键的设计特性使得它成为从出生就开始自带光环:

  • 可移植 - 前面也提到了 WASM 最初是为 Web 设计的,目前几乎所有主流的浏览器都提供对 WASM 的支持;此外 WASM 也是针对低级虚拟机架构而设计,其指令由物理机单独翻译成机器代码,这就意味着 WASM 二进制文件最终可以在各种操作系统和芯片架构的组合上运行,无论是 Linux、MacOS、Windows等操作系统,还是ARM、X86、Power等芯片架构中,甚至移动设备、物联网(IoT)设备都可以运行。
  • 轻量切且高效 - 前面提到了 WASM 的静态类型和编译优化,使得它相对于 JavaScript 以及 asm.js 有着数倍的性能提升。这种性能上的优势也让 WASM 在浏览器之外的运行环境中带来复利,WASM 特别适合对冷启动有较高要求的 Serverless 应用场景;目前,Serverless 技术虽然可以帮助管理基础计算设施和分拨配资源,但是在冷启动的情况下,还是需要新的计算资源,从而带来额外的成本,而 WASM 模块的轻量高效特性使得冷启动的成本大大缩减。
  • 安全 - WASM 运行在沙盒环境中,重视能力驱动的安全性,对主机系统资源(如文件系统,硬件等)的访问是受限制的,除非被授予明确的能力访问,所以 WASM 减少了攻击面,实现了多租户环境中不受信任的代码安全受限地执行。这种安全模式允许开发者使用插件和用户提交的代码来扩展现有的应用程序。
  • 多语言支持 - WASM 是一种编译目标格式,它无关于编程语言,只要语言支持,开发者可以灵活地使用多种语言(如 C、C++、Rust、Go等)来构建 WASM。目前,在 RedMonk 排名前 20 的编程语言几乎都在添加 WASM 的支持。

WebAssembly 使用场景

  1. 应用向浏览器端迁移

WASM 之前,JavaScript 是浏览器端的主要编程语言,但由于 JavaScript 本身的性能问题,导致很多大型应用没有办法直接运行在浏览器端。而如今随着浏览器和前端框架对 WASM 的支持,使开发者更容易在浏览器中编译和执行其他流行语言,例如 C、C++、Rust、和 Go 等语言。甚至也出现了从 WASM 设计的语言,包括 AssemblyScript、Grain、Motoko等。还有些企业开始使用 WASM 将之前的桌面应用迁移到浏览器端,例如 Google Earth、Photoshop、AutoCAD 等等,还有一些成熟的视频和游戏项目,如 Unity WebGL、Unreal Engine等。随着 WASM 系统接口 WASI 的不断完善,WASM 模块与操作系统之间的交将被标准化,WASM 程序将以一致的方式访问系统资源。

  1. 服务器端
  • Serverless - 无服务平台高度依赖优化的冷启动技术,所以 WASM 的轻量高效特性使得 WASM 运行时(如 WASMEdge)非常适合为下一代无服务器平台提供动力,这也使得 WASM 不断向边缘计算领域渗透。
  • 边缘的数据分析和机器学习 - WASM 可移植性和高效特性使得它适合于应用在支持边缘的机器学习场景,WASM 机器学习模块可以部署在外形和计算能力差异很大的边缘设备上,数据计算接近于数据产生源,无论是运行在网络边缘还是设备边缘。
  • 服务网格 - 利用 WASM 的灵活性可以将服务网格(如 Istio)的扩展能力从控制平面下沉到数据平面(如使用 WASM 扩展 Envoy),WASM 扩展本身运行在沙盒环境中,不会影响数据平面程序的运行,资源访问也是受限的。
  • 平台扩展 - 得益于 WASM 的多语言支持和沙盒隔离技术, WASM 可以在现有的应用程序上提供一个可扩展的模型和执行第三方(可信或不可信)代码的能力。

WASM 生态圈 Landscape:

wasm_landscape.png

WebAssembly 与容器技术的融合

相信随着技术的迭代,WASM 运行时将会与容器运行时一样成为云原生领域的“一等公民”,随着 WASI 的不断完善以及容器注册表(OCI Registry)对 WASM 程序模块的支持,WASM 也许会将应用程序的管理提高到新的高度,就像从虚拟机技术到容器的普及,WASM 或许会替代一部分容器技术的功能。借助于 WASM 的冷启动优化,WASM 容器将会非常适合寿命较短的无服务器和边缘工作负载;但是传统的 容器工作负载将致力于需要大量 I/O 或需要访问网络套接字的长期运行的服务(如缓存服务器)。

更进一步地讲,Kubernetes 这样主流的容器编排引擎与如何与 WASM 进行整合,虽然为时尚早,但是我们已经看到了例如 Krustlet、runwasi、Containerd WASM Shims 以及 crun 的 WASM 处理程序等项目的涌现,它们的目标都是将 WASM 提升为容器环境中的一等公民,将其作为 Kubernetes 新的运行时。