部署基于 WebAssembly 的高性能 Serverless 云函数
Posted TencentServerless
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了部署基于 WebAssembly 的高性能 Serverless 云函数相关的知识,希望对你有一定的参考价值。
放眼未来,我们认为 WebAssembly Runtime 是一个可以在很多场景替代 Docker 的轻量级软件容器。WebAssembly 在速度(尤其是冷启动)与资源占用上大大优于 Docker(上百倍的改进)。但是,罗马不是一天建成的。今天腾讯云支持的容器镜像只有 Docker 镜像一种,我们暂时必须在 Docker 里面运行 WebAssembly。
-
WebAssembly 函数可以实现接近机器语言的性能。 -
与 NaCl 函数不同,WebAssembly 函数是跨平台的。允许开发者在自己的电脑上测试函数,然后部署在任何服务器,硬件架构,公共云,或者容器上。 -
WebAssembly 函数可以简单地被打包,部署,更新升级,编排。远比 NaCl 动态库容易管理。 -
WebAssembly 比 NaCl 函数更安全,因为 WebAssembly 提供了一个安全隔离的沙箱。
模板链接:https://github.com/second-state/tencent-scf-wasm-runtime
$ rustup target add wasm32-wasi
链接:https://github.com/second-state/tencent-scf-wasm-runtime#%E5%89%8D%E7%AB%AF%E7%9A%84-web-ui
api/grayscale.wasm
文件里。这个函数的 Rust 源代码在
api/functions/image-grayscale
里面。
STDIN
读入上传的图片,然后把黑白图片从
STDOUT
输出。其输入与输出都是二进制数组。
use std::io::{self, Read, Write};
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();
}
cargo
命令就可以编译出新的 WebAssembly 文件
api/grayscale.wasm
。
$ cd api/functions/image-grayscale/
$ cargo build --release --target wasm32-wasi
$ cp target/wasm32-wasi/release/grayscale.wasm ../../
api/server.js
这个脚本从 Web Function 的网关获得 HTTP request 的数据,传给
grayscale.wasm
函数执行,再把执行结果返回给 HTTP response。
说明:WasmEdge 支持 AOT 编译,大幅提升了应用的性能,因此在这里,我们使用 WasmEdge AOT 编译器在 Docker 环境内生成的 grayscale.so 文件,
app.post('/func', (req, res) => {
const wasmedge = spawn(path.join(__dirname, 'wasmedge'), [path.join(__dirname, 'grayscale.so')]);
let d = [];
wasmedge.stdout.on('data', (data) => {
d.push(data);
grayscale.wasm
与
server.js
以及 WasmEdge 的执行环境一起封装在一个容器镜像里面。
$ cd api
$ docker build -t hkccr.ccs.tencentyun.com/secondstate/grayscale:0.1 ./
... ...
Successfully tagged hkccr.ccs.tencentyun.com/secondstate/grayscale:0.1
这里的 hkccr.ccs.tencentyun.com/secondstate/grayscale
是在腾讯云的容器服务上建立一个容器镜像后获得的,具体可以参考我们的 README — 准备工作。
$ docker push hkccr.ccs.tencentyun.com/secondstate/grayscale:0.1
The push refers to repository [hkccr.ccs.tencentyun.com/secondstate/grayscale]
... ...
0.1: digest: sha256:... size: 3246
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.");
}
}
api/server.js
将 HTTP request 与 response 与 WasmEdge 连接起来。如果我们更改了 Rust 函数的输入与输出,可能也需要改动
api/server.js
里面的胶水代码。
app.post('/func', (req, res) => {
const wasmedge = spawn(
path.join(__dirname, 'wasmedge-tensorflow-lite'),
[path.join(__dirname, 'classify.so')],
{env: {'LD_LIBRARY_PATH': __dirname}}
);
Rust 函数
与
api/server.js
之后,按照上文所说的方法,重新创建与部署 Docker 镜像,新的函数就可以用了!
链接:https://github.com/second-state/tencent-scf-wasm-runtime/blob/main/README.md
GitHub: github.com/serverless 官网: cloud.tencent.com/product/serverless-catalog
以上是关于部署基于 WebAssembly 的高性能 Serverless 云函数的主要内容,如果未能解决你的问题,请参考以下文章
使用 Docker 管理用 Rust 编写的 WebAssembly 程序
Chromium 宣布:再见 PNaCI,你好 WebAssembly!