Netlify 中的 WebAssembly Serverless 函数
ztj100 2024-11-17 04:04 26 浏览 0 评论
Netlify 是一个开发和托管 Jamstack 应用的平台。实际上,Jamstack 是Netlify 的创始人 Mathias Biilmann 于 2015年造出来的一个词。 Netlify 也是 JamstackConf 的主要组织者。
Jamstack 应用程序由一个静态 UI (HTML 和 JavaScript) 和一系列 serverless 函数组成。动态 UI 元素由 JavaScript 向 serverless 函数获取数据生成。Jamstack 的好处有很多,但这其中最重要的好处之一是性能绝佳。由于 UI 不再从中心服务器的 runtime 生成,因此服务器上的负载要少得多,我们可以通过边缘网络(例如 CDN)部署 UI。
但是边缘 CDN 只解决了分发静态 UI 文件的问题。后端 serverless 函数可能仍然很慢。事实上,流行的 Serverless 平台存在众所周知的性能问题,例如冷启动缓慢,尤其是对于交互式应用程序而言。在这方面, WebAssembly 大有可为。
使用由 CNCF 托管的云原生 WebAssembly runtime WasmEdge ,开发者可以编写部署在公共云或边缘计算节点上的高性能serverless 函数。本文中,我们将探索如何使用 Rust 编写的 WasmEdge 函数来支持 Netlify 应用程序后端。
为什么用 WebAssembly 实现 Netlify 函数
Netlify 平台已经有一个非常易于使用的用于部署函数的 serverless 框架。正如上面讨论的,使用 WebAssembly 以及 WasmEdge 是为了进一步提高性能。用 C/C++、Rust 和 Swift 写的高性能函数可以轻松编译成 WebAssembly。这些 WebAssembly 函数比 serverless 函数中常用的 JavaScript 或 Python 快得多。
可是,如果原始性能是唯一的目标,为什么不直接将这些函数编译为机器本地可执行文件呢(本地客户端或者 NaCl)?这是因为 Netlify 已经在使用 Firecracker microVM 在 AWS Lambda 中安全地运行这些函数。
我们对未来的愿景是在云原生基础架构中将 WebAssembly 作为轻量级的 runtime 与 Docker 、 microVM 并列运行。与类似 Docker 容器或 microVM 相比,WebAssembly 提供更高的性能并消耗更少的资源。但就目前而言,Netlify 仅支持在 microVM 中运行 WebAssembly。
相比运行容器化 NaCl 程序,在 microVM 中运行 WebAssembly 函数有很多优势。
首先,WebAssembly 为独立的函数提供了细颗粒度的 runtime 隔离。一个微服务可以有多个函数,并支持在 microVM 中运行的服务。 WebAssembly 可以让微服务更安全、更稳定。
第二,WebAssembly 字节码是可移植的。开发者只需构建一次,无需担心未来底层 Netlify serverless runtime 的改变或更新。它还允许开发者在其它云环境中重复使用相同的 WebAssembly 函数。
第三, WebAssembly 应用很容易部署和管理。与 NaCl 动态库和可执行文件相比,它们具有更少的平台依赖性和复杂性。
最后, WasmEdge Tensorflow API 提供了最符合 Rust 规范的、执行 Tensorflow 模型的方式。WasmEdge 安装了 Tensorflow 依赖库的正确组合,并为开发者提供了统一的 API。
概念和解释说了很多,趁热打铁,我们来看看示例应用吧!
准备工作
由于我们的 demo WebAssembly 函数是用 Rust 编写的,因此您需要安装 Rust 编译器。确保按如下方式安装 wasm32-wasi 编译器目标,以生成 WebAssembly 字节码。
$ rustup target add wasm32-wasi
demo 应用前端是用 Next.js 写的,并且部署在 Netlify 上。我们假设你已经有使用 Next.js 和 Netlify 的基本知识了。
示例 1: 图片处理
我们的第一个 demo 应用程序是让用户上传图片,然后调用 serverless 函数将其变成黑白图片。 开始之前,你可以试用一下这个部署在 Netlify 上的 demo。
首先 fork demo 应用的 GitHub repo 。 要将该应用部署到 Netlify,只需将你的 GitHub repo 添加到 Netlify 上。
这个 repo 是 Netlify 平台的标准 Next.js 应用程序。后端 serverless 函数在 api/functions/image_grayscale 文件夹中。 src/main.rs 文件包含 Rust 程序的源代码。 Rust 程序从 STDIN 读取图片数据,然后将黑白图片输出到 STDOUT。
use hex;
use std::io::{self, Read};
use image::{ImageOutputFormat, ImageFormat};
fn main() {
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf).unwrap();
let image_format_detected: ImageFormat = image::guess_format(&buf).unwrap();
let img = image::load_from_memory(&buf).unwrap();
let filtered = img.grayscale();
let mut buf = vec![];
match image_format_detected {
ImageFormat::Gif => {
filtered.write_to(&mut buf, ImageOutputFormat::Gif).unwrap();
},
_ => {
filtered.write_to(&mut buf, ImageOutputFormat::Png).unwrap();
},
};
io::stdout().write_all(&buf).unwrap();
io::stdout().flush().unwrap();
}
使用 Rust 的 cargo 工具将 Rust 程序构建为为 WebAssembly 字节码或者原生代码。
$ cd api/functions/image-grayscale/
$ cargo build --release --target wasm32-wasi
将 build artifacts 复制到 api 文件夹。
$ cp target/wasm32-wasi/release/grayscale.wasm ../../
Netlify 函数在设置 serverless 函数时运行 api/pre.sh 。 这时会安装 WasmEdge runtime,然后将 WebAssembly 字节码程序编译为一个本地的 so 库,从而更快地执行。
api/hello.js 文本加载 WasmEdge runtime,在 WasmEdge 中启动编译好的 WebAssembly 程序,并通过 STDIN 传递上传的图像数据。这里请注意, api/hello.js 会运行由 api/pre.sh 生成的编译好的 grayscale.so 文件,从而得到更好的性能。
const fs = require('fs');
const { spawn } = require('child_process');
const path = require('path');
module.exports = (req, res) => {
const wasmedge = spawn(
path.join(__dirname, 'wasmedge'),
[path.join(__dirname, 'grayscale.so')]);
let d = [];
wasmedge.stdout.on('data', (data) => {
d.push(data);
});
wasmedge.on('close', (code) => {
let buf = Buffer.concat(d);
res.setHeader('Content-Type', req.headers['image-type']);
res.send(buf);
});
wasmedge.stdin.write(req.body);
wasmedge.stdin.end('');
}
这样就完成了。 接下来将 repo 部署到Netlify ,就得到了一个 Jamstack 应用。该应用有着基于 Rust 和 WebAssembly 的高性能 serverless 后端。
示例 2: AI 推理
第二个demo应用让用户上传图像,然后调用 serverless 函数来识别图片中的主要物体。
它与上一个示例在同一个 GitHub repo ,但是在 tensorflow 分支。 用于图片识别的后端 serverless 函数在该分支的 api/functions/image-classification 文件夹中。 src/main.rs 文件包含了 Rust 程序的源代码。 Rust 程序从 STDIN 读取图像数据,然后将文本输出输出到 STDOUT。 它用 WasmEdge Tensorflow API 来运行 AI 推理。
pub fn main() {
// Step 1: Load the TFLite model
let model_data: &[u8] = include_bytes!("models/mobilenet_v1_1.0_224/mobilenet_v1_1.0_224_quant.tflite");
let labels = include_str!("models/mobilenet_v1_1.0_224/labels_mobilenet_quant_v1_224.txt");
// Step 2: Read image from STDIN
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf).unwrap();
// Step 3: Resize the input image for the tensorflow model
let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(&buf, 224, 224);
// Step 4: AI inference
let mut session = wasmedge_tensorflow_interface::Session::new(&model_data, wasmedge_tensorflow_interface::ModelType::TensorFlowLite);
session.add_input("input", &flat_img, &[1, 224, 224, 3])
.run();
let res_vec: Vec<u8> = session.get_output("MobilenetV1/Predictions/Reshape_1");
// Step 5: Find the food label that responds to the highest probability in res_vec
// ... ...
let mut label_lines = labels.lines();
for _i in 0..max_index {
label_lines.next();
}
// Step 6: Generate the output text
let class_name = label_lines.next().unwrap().to_string();
if max_value > 50 {
println!("It {} a <a href='https://www.google.com/search?q={}'>{}</a> in the picture", confidence.to_string(), class_name, class_name);
} else {
println!("It does not appears to be any food item in the picture.");
}
}
使用 cargo 工具将 Rust 程序构建为 WebAssembly 字节码或原生代码。
$ cd api/functions/image-classification/
$ cargo build --release --target wasm32-wasi
将 build artifacts 复制到 api 文件夹中
$ cp target/wasm32-wasi/release/classify.wasm ../../
同样, api/pre.sh 脚本在此应用程序中安装 WasmEdge runtime 及其 Tensorflow 依赖项。同时在部署时,它将 classify.wasm 字节码程序编译为 classify.so 本地共享库。
api/hello.js 脚本加载 WasmEdge runtime,在 WasmEdge 中启动编译好的 WebAssembly 程序,并通过 STDIN 传递已上传的图像数据。 注意 api/hello.js 运行由 api/pre.sh 生成的编译好的 classify.so 文件,以达到更好的性能。
const fs = require('fs');
const { spawn } = require('child_process');
const path = require('path');
module.exports = (req, res) => {
const wasmedge = spawn(
path.join(__dirname, 'wasmedge-tensorflow-lite'),
[path.join(__dirname, 'classify.so')],
{env: {'LD_LIBRARY_PATH': __dirname}}
);
let d = [];
wasmedge.stdout.on('data', (data) => {
d.push(data);
});
wasmedge.on('close', (code) => {
res.setHeader('Content-Type', `text/plain`);
res.send(d.join(''));
});
wasmedge.stdin.write(req.body);
wasmedge.stdin.end('');
}
现在可以将你fork 的 repo 部署到 Netlify 上,并得到一个可以进行物体识别的 web 应用。
接下来呢?
在 Netlify 目前的 serverless 容器中运行 WasmEdge 是目前将高性能函数添加到 Netlify 应用中的简单方式。未来更好的方法是将WasmEdge作为容器本身使用,这样就无须 Docker 与 Node.js,我们可以以更高的效率运行 serverless 函数。 WasmEdge 已经与 Docker 工具兼容。如果你有兴趣加入 WasmEdge 和 CNCF 进行这个激动人心的工作,欢迎加入我们的 channel!
相关推荐
- 这个 JavaScript Api 已被废弃!请慎用!
-
在开发过程中,我们可能会不自觉地使用一些已经被标记为废弃的JavaScriptAPI。这些...
- JavaScript中10个“过时”的API,你的代码里还在用吗?
-
JavaScript作为一门不断发展的语言,其API也在持续进化。新的、更安全、更高效的API不断涌现,而一些旧的API则因为各种原因(如安全问题、性能瓶颈、设计缺陷或有了更好的替代品)被标记为“废...
- 几大开源免费的 JavaScript 富文本编辑器测评
-
MarkDown编辑器用的时间长了,发现发现富文本编辑器用起来是真的舒服。...
- 比较好的网页里面的 html 编辑器 推荐
-
如果您正在寻找嵌入到网页中的HTML编辑器,以便用户可以直接在网页上编辑HTML内容,以下是几个备受推荐的:CKEditor:CKEditor是一个功能强大的、开源的富文本编辑器,可以嵌入到...
- Luckysheet 实现excel多人在线协同编辑
-
前言前些天看到Luckysheet支持协同编辑Excel,正符合我们协同项目的一部分,故而想进一步完善协同文章,但是遇到了一下困难,特此做声明哈,若侵权,请联系我删除文章!若侵犯版权、个人隐私,请联系...
- 从 Element UI 源码的构建流程来看前端 UI 库设计
-
作者:前端森林转发链接:https://mp.weixin.qq.com/s/ziDMLDJcvx07aM6xoEyWHQ引言...
- 手把手教你如何用 Decorator 装饰你的 Typescript?「实践」
-
作者:Nealyang转发连接:https://mp.weixin.qq.com/s/PFgc8xD7gT40-9qXNTpk7A...
- 推荐五个优秀的富文本编辑器
-
富文本编辑器是一种可嵌入浏览器网页中,所见即所得的文本编辑器。对于许多从事前端开发的小伙伴来说并不算陌生,它的应用场景非常广泛,平时发个评论、写篇博客文章等都能见到它的身影。...
- 基于vue + element的后台管理系统解决方案
-
作者:林鑫转发链接:https://github.com/lin-xin前言该方案作为一套多功能的后台框架模板,适用于绝大部分的后台管理系统(WebManagementSystem)开发。基于v...
- 开源富文本编辑器Quill 2.0重磅发布
-
开源富文本编辑器Quill正式发布2.0版本。官方TypeScript声明...
- Python之Web开发框架学习 Django-表单处理
-
在Django中创建表单实际上类似于创建模型。同样,我们只需要从Django类继承,则类属性将是表单字段。让我们在myapp文件夹中添加一个forms.py文件以包含我们的应用程序表单。我们将创建一个...
- Django测试入门:打造坚实代码基础的钥匙
-
这一篇说一下django框架的自动化测试,...
- Django ORM vs SQLAlchemy:到底谁更香?从入门到上头的选择指南
-
阅读文章前辛苦您点下“关注”,方便讨论和分享,为了回馈您的支持,我将每日更新优质内容。...
- 超详细的Django 框架介绍,它来了!
-
时光荏苒,一晃小编的Tornado框架系列也结束了。这个框架虽然没有之前的FastAPI高流量,但是,它也是小编的心血呀。总共16篇博文,从入门到进阶,包含了框架的方方面面。虽然小编有些方面介绍得不是...
- 20《Nginx 入门教程》使用 Nginx 部署 Python 项目
-
今天的目标是完成一个PythonWeb项目的线上部署,我们使用最新的Django项目搭建一个简易的Web工程,然后基于Nginx服务部署该PythonWeb项目。1.前期准备...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)