Netlify 中的 WebAssembly Serverless 函数
ztj100 2024-11-17 04:04 12 浏览 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!
相关推荐
- Whoosh,纯python编写轻量级搜索工具
-
引言在许多应用程序中,搜索功能是至关重要的。Whoosh是一个纯Python编写的轻量级搜索引擎库,可以帮助我们快速构建搜索功能。无论是在网站、博客还是本地应用程序中,Whoosh都能提供高效的全文搜...
- 如何用Python实现二分搜索算法(python二分法查找代码)
-
如何用Python实现二分搜索算法二分搜索(BinarySearch)是一种高效的查找算法,适用于在有序数组中快速定位目标值。其核心思想是通过不断缩小搜索范围,每次将问题规模减半,时间复杂度为(O...
- 路径扫描 -- dirsearch(路径查找器怎么使用)
-
外表干净是尊重别人,内心干净是尊重自己,干净,在今天这个时代,应该是一种极高的赞美和珍贵。。。----网易云热评一、软件介绍Dirsearch是一种命令行工具,可以强制获取web服务器中的目录和文件...
- 78行Python代码帮你复现微信撤回消息!
-
来源:悟空智能科技本文约700字,建议阅读5分钟。本文基于python的微信开源库itchat,教你如何收集私聊撤回的信息。...
- 从零开始学习 Python!2《进阶知识》 Python进阶之路
-
欢迎来到Python学习的进阶篇章!如果你说已经掌握了基础语法,那么这篇就是你开启高手之路的大门。我们将一起探讨面向对象编程...
- 白帽黑客如何通过dirsearch脚本工具扫描和收集网站敏感文件
-
一、背景介绍...
- Python之txt数据预定替换word预定义定位标记生成word报告(四)
-
续接Python之txt数据预定替换word预定义定位标记生成word报告(一)https://mp.toutiao.com/profile_v4/graphic/preview?pgc_id=748...
- Python——字符串和正则表达式中的反斜杠('\')问题详解
-
在本篇文章里小编给大家整理的是关于Python字符串和正则表达式中的反斜杠('\')问题以及相关知识点,有需要的朋友们可以学习下。在Python普通字符串中在Python中,我们用'\'来转义某些普通...
- Python re模块:正则表达式综合指南
-
Python...
- python之re模块(python re模块sub)
-
re模块一.re模块的介绍1.什么是正则表达式"定义:正则表达式是一种对字符和特殊字符操作的一种逻辑公式,从特定的字符中,用正则表达字符来过滤的逻辑。(也是一种文本模式;)2、正则表达式可以帮助我们...
- MySQL、PostgreSQL、SQL Server 数据库导入导出实操全解
-
在数字化时代,数据是关键资产,数据库的导入导出操作则是连接数据与应用场景的桥梁。以下是常见数据库导入导出的实用方法及代码,包含更多细节和特殊情况处理,助你应对各种实际场景。一、MySQL数据库...
- Zabbix监控系统系列之六:监控 mysql
-
zabbix监控mysql1、监控规划在创建监控项之前要尽量考虑清楚要监控什么,怎么监控,监控数据如何存储,监控数据如何展现,如何处理报警等。要进行监控的系统规划需要对Zabbix很了解,这里只是...
- mysql系列之一文详解Navicat工具的使用(二)
-
本章内容是系列内容的第二部分,主要介绍Navicat工具的使用。若查看第一部分请见:...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Whoosh,纯python编写轻量级搜索工具
- 如何用Python实现二分搜索算法(python二分法查找代码)
- 路径扫描 -- dirsearch(路径查找器怎么使用)
- 78行Python代码帮你复现微信撤回消息!
- 从零开始学习 Python!2《进阶知识》 Python进阶之路
- 白帽黑客如何通过dirsearch脚本工具扫描和收集网站敏感文件
- Python之txt数据预定替换word预定义定位标记生成word报告(四)
- 假期苦短,我用Python!这有个自动回复拜年信息的小程序
- Python——字符串和正则表达式中的反斜杠('\')问题详解
- Python re模块:正则表达式综合指南
- 标签列表
-
- 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)
- node卸载 (33)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- exceptionininitializererror (33)
- 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)