百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

Netlify 中的 WebAssembly Serverless 函数

ztj100 2024-11-17 04:04 33 浏览 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!

相关推荐

离谱!写了5年Vue,还不会自动化测试?

前言大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。Playwright是一个功能强大的端到...

package.json 与 package-lock.json 的关系

模块化开发在前端越来越流行,使用node和npm可以很方便的下载管理项目所需的依赖模块。package.json用来描述项目及项目所依赖的模块信息。那package-lock.json和...

Github 标星35k 的 SpringBoot整合acvtiviti开源分享,看完献上膝盖

前言activiti是目前比较流行的工作流框架,但是activiti学起来还是费劲,还是有点难度的,如何整合在线编辑器,如何和业务表单绑定,如何和系统权限绑定,这些问题都是要考虑到的,不是说纯粹的把a...

Vue3 + TypeScript 前端研发模板仓库

我们把这个Vue3+TypeScript前端研发模板仓库的初始化脚本一次性补全到可直接运行的状态,包括:完整的目录结构所有配置文件研发规范文档示例功能模块(ExampleFeature)...

Vue 2迁移Vue 3:从响应式到性能优化

小伙伴们注意啦!Vue2已经在2023年底正式停止维护,再不升级就要面临安全漏洞没人管的风险啦!而且Vue3带来的性能提升可不是一点点——渲染速度快40%,内存占用少一半,更新速度直接翻倍!还在...

VUE学习笔记:声明式渲染详解,对比WEB与VUE

声明式渲染是指使用简洁的模板语法,声明式的方式将数据渲染进DOM系统。声明式是相对于编程式而言,声明式是面向对象的,告诉框架做什么,具体操作由框架完成。编程式是面向过程思想,需要手动编写代码完成具...

苏州web前端培训班, 苏州哪里有web前端工程师培训

前端+HTML5德学习内容:第一阶段:前端页面重构:PC端网站布局、HTML5+CSS3基础项目、WebAPP页面布局;第二阶段:高级程序设计:原生交互功能开发、面向对象开发与ES5/ES6、工具库...

跟我一起开发微信小程序——扩展组件的代码提示补全

用户自定义代码块步骤:1.HBuilderX中工具栏:工具-代码块设置-vue代码块2.通过“1”步骤打开设置文件...

JimuReport 积木报表 v1.9.3发布,免费可视化报表

项目介绍积木报表JimuReport,是一款免费的数据可视化报表,含报表、大屏和仪表盘,像搭建积木一样完全在线设计!功能涵盖:数据报表、打印设计、图表报表、门户设计、大屏设计等!...

软开企服开源的无忧企业文档(V2.1.3)产品说明书

目录1....

一款面向 AI 的下一代富文本编辑器,已开源

简介AiEditor是一个面向AI的下一代富文本编辑器。开箱即用、支持所有前端框架、支持Markdown书写模式什么是AiEditor?AiEditor是一个面向AI的下一代富文本编辑...

玩转Markdown(2)——抽象语法树的提取与操纵

上一篇玩转Markdown——数据的分离存储与组件的原生渲染发布,转眼已经鸽了大半年了。最近在操纵mdast生成md文件的时候,心血来潮,把玩转Markdown(2)给补上了。...

DeepseekR1+ollama+dify1.0.0搭建企业/个人知识库(入门避坑版)

找了网上的视频和相关文档看了之后,可能由于版本不对或文档格式不对,很容易走弯路,看完这一章,可以让你少踩三天的坑。步骤和注意事项我一一列出来:1,前提条件是在你的电脑上已配置好ollama,dify1...

升级JDK17的理由,核心是降低GC时间

升级前后对比升级方法...

一个vsCode格式化插件_vscode格式化插件缩进量

ESlint...

取消回复欢迎 发表评论: