本文将介绍一种新的 Serverless 架构:基于 WebAsssembly 虚拟机的 Serverless 架构。通过本文,你会了解到 WebAssembly 技术、Serverless WebAssembly 架构、如何使用 Serverless WebAssembly 开发一个简单的应用程序。
先来看一个 MobileNet TensorFlow model 在 Serverless Wasm 的实例。上传一张食物照片,识别图片里的食物是什么。
点击这里,上传你的午餐,将自动识别你中午吃了什么!
在 Serverless 架构中,开发者与用户无需关注服务器的运维与费用,而是将关注点投入在实现业务逻辑的代码上,并按实际资源使用量交费。在不降低用户体验的前提下,Serverless 极大降低了开发与运营的成本。
Serverless 云函数是今天实现互联网应用的最快捷最简单的方法。国内外各大云厂商都有自己的 Serverless 业务,或架构在系统或硬件级别的虚拟机,或建立在容器,如 Docker 之上。
这两种方法在安全与性能上各有千秋。根据伯克利大学的 Johann Schleier-Smith 的观点,使用系统或硬件级别的虚拟机提供了最佳的隔离和安全性,但是运行很慢,并且管理起来很复杂。使用容器的方法安全性比较差,但是性能比系统级虚拟机高得多。
除了上面两种 Serverless 架构外,还有一种新兴的方法:使用特定于应用程序的虚拟机,比如 WebAssembly(Wasm) 。
我在《为什么说软件服务的未来必然是WebAssembly?》一文中介绍过 WebAssembly 在服务端的巨大潜力。一言以概之,WebAssembly 提供了接近了接近本机代码的性能,但是依然保持着良好的安全性。
如果在 2008 年已经有了 WASM + WASI,那么我们压根无需创始 Docker 这个项目了。Wasm 就有这么重要!服务器上的 WebAssembly 是计算的未来。— Docker 联合创始人 Solomon Hykes
Serverless Wasm 提供了高度的抽象,用户不需要绑定自己的操作系统或软件堆栈,只需执行编译后的字节码应用程序。WebAssembly 提供了一个高级的“基于功能”的安全模型,用于访问系统资源(例如,通过WASI 规范),而不是粗粒度的操作系统级隔离。
接下来让我们以 Second State FaaS 为例,具体了解下 Serverless Wasm 架构。
Serverless Wasm 的不足之处在于,只支持能够编译为 Wasm 字节码的应用程序,目前 Rust、C、C++、AssemblyScript 是支持 Wasm 最完善的语言。但是随着 Wasm 的生态不断完善发展,Wasm 通过 LLVM 工具链将支持更多的编程语言。
Second State FaaS 目前把重点放在了对 Rust 函数的支持。Rust 连续5年被 Stack OverFlow 评为最受开发者欢迎的编程语言。Rust 是安全的、高性能的,内存安全的,没有GC。
Serverless Wasm 的整个工作流是这样的:
使用编译工具 ssvmup 将 Rust 函数编译成 wasm 字节码
通过 HTTP POST 将编译好的 .wasm
文件上传到 FaaS 中
得到返回的 wasm_id、wasm_sha256、SSVM_Usage_Key、SSVM_Admin_Key,用于管理当前的应用程序
最后通过 HTTP API 调用、执行 Rust 函数
Rust 函数与 Wasm 虚拟机的结合非常适合计算密集的任务,比如 AI 推理、视频转码、边缘计算等场景。
接下来一起用 Serverless Wasm 实现一个简单的 Hello World 示例。
1 使用 Docker image。下面这个 Docker image 包含了所有需要的工具链
$ docker pull secondstate/ssvm-nodejs-starter:v2$ docker run -p 3000:3000 --rm -it -v $(pwd):/app secondstate/ssvm-nodejs-starter:v2(docker) # ssvmup build... ...
2 在github 上 fork 这个repo,然后使用 GitHub 新发布的 GitHub CodeSpaces 打开 Hello World 示例。在这个 IDE 里,你可以重写 Rust 函数,然后在 terminal window 运行命令行。
3 如果你安装了 Ubuntu Linux 20.04,只需再安装 Rust 以及 ssvmup
源代码可以在这里查看
https://github.com/second-state/wasm-learning/tree/master/faas/hello
下面是 Hello World 的完整 Rust 代码。这个 Rust 函数接收一个字符串参数并返回一个字符串值。Hello 是输入参数的前缀,然后将字符串返回给函数的调用者。
use wasm_bindgen::prelude::*;#[wasm_bindgen]pub fn say(s: &str) -> String {
let r = String::from("hello "); return r + s;}
编译之前,请确保 Cargo.toml 文件声明了正确的依赖关系。
[dependencies]wasm-bindgen = "=0.2.61"
使用 ssvvmup 工具将 Rust 函数编译成 WebAssembly 函数。使用下面的命名行,编译好的 wasm 文件将保存在pkg目录中。
$ ssvmup build
将在 pkg
目录的 .wasm
文件上传到 Second State FaaS 中的 /api/executables
RPC 服务端点中。上传之前,记得检查 .wasm
的文件名。
$ curl --location --request POST 'https://rpc.ssvm.secondstate.io:8081/api/executables' \--header 'Content-Type: application/octet-stream' \--header 'SSVM-Description: say hello' \--data-binary '@pkg/hello_lib_bg.wasm'
.wasm
文件上传完成后,Second State FaaS 将返回 wasm_id
。wasm_id
可以访问已经部署好的 wasm 文件里的函数。
现在可以通过 web 调用 Rust 函数了!RPC 服务端点在 /api/run/wasm_id/function_name
,其中 wasm_id
是刚刚部署的 Wasm 文件的 ID,function_name
是我们要在 wasm 文件中调用的函数名称。
HTTP request body 作为调用参数会传递给函数。如我们所见,这个函数采用字符串参数,因此 HTTP body 会被转换为文本字符串并传递给该函数。TTP response body 是该函数的返回字符串值。
$ curl --location --request POST 'https://rpc.ssvm.secondstate.io:8081/api/run/161/say' \--header 'Content-Type: text/plain' \--data-raw 'Second State FaaS'hello Second State FaaS
FaaS 最引人注目的用例之一是使函数充当静态网站的后端服务。下面是对此 FaaS 函数进行 AJAX 调用的 JavaScript 代码。
$.ajax({
url: "https://rpc.ssvm.secondstate.io:8081/api/run/161/say", type: "post", data : $('#input').val(), contentType: "text/plain", processData: false, success: function (data) {
$('#result').html(data); }});
点击这里可以访问有 Web UI 的演示。serverless 函数将静态函数转换为 web 应用程序。
这样,我们就完成了 serverless wasm 的一个简单例子。如果你对 serverless wasm 感兴趣,欢迎访问 serverless wasm 网站,了解更多 serverless wasm 在 AI 推理上的应用实例与教程。
文档:将 Binary 数据作为函数的输入和输出
文档:调用参数时混合使用文本和 Binary 数据
文档:webhooks
文档:HTTP Proxy
实例:使用 serverless wasm 添加水印
实例:使用 serverless wasm 添加自定义水印
实例:使用 serverless wasm 发送邮件
实例:使用 serverless wasm 进行图片识别
实例:使用 serverless wasm 进行人脸识别