Бессерверные функции Rust и WebAssembly в Vercel

задняя часть Rust Serverless
Бессерверные функции Rust и WebAssembly в Vercel

Vercelразрабатывается и размещаетсяJamstackВедущая платформа для приложений. В отличие от традиционных веб-приложений, которые динамически генерируют пользовательский интерфейс с сервера во время выполнения, приложения Jamstack состоят из статического пользовательского интерфейса (HTML и JavaScript) и набора бессерверных функций, поддерживающих динамические элементы пользовательского интерфейса с помощью JavaScript.

Подход Jamstack имеет много преимуществ. Одним из наиболее важных преимуществ этого является его мощная производительность. Поскольку пользовательский интерфейс больше не генерируется из среды выполнения центрального сервера, нагрузка на сервер намного меньше, и мы можем развернуть пользовательский интерфейс через пограничную сеть, такую ​​как CDN.

Однако пограничные CDN решают только проблему распространения статических файлов пользовательского интерфейса. Бессерверные функции на серверной части могут по-прежнему работать медленно. На самом деле популярные бессерверные платформы имеют хорошо известные проблемы с производительностью, такие как медленный холодный запуск, особенно для интерактивных приложений. В этом отношении WebAssembly может многое предложить.

использоватьWasmEdge,ОдинОблачная среда выполнения WebAssembly, размещенная на CNCF, разработчики могут писать высокопроизводительные бессерверные функции и развертывать их в общедоступном облаке или на периферийных вычислительных узлах. В этой статье мы рассмотрим, как использовать функции WasmEdge, написанные на Rust, для управления серверной частью приложения Vercel.

Зачем использовать WebAssembly в Vercel Serverless?

Платформа Vercel уже имеет очень простой в использованииserverlessFramework, который может развертывать функции, размещенные в Vercel. Как обсуждалось выше, использование WebAssembly и WasmEdge предназначено дляДальнейшее улучшение производительности. Высокопроизводительные функции, написанные на C/C++, Rust и Swift, можно легко скомпилировать в WebAssembly. Эти функции WebAssembly намного быстрее, чем JavaScript или Python, обычно используемые в бессерверных функциях.

Итак, вопрос в том, что, если единственная цель — чистая производительность, почему бы просто не скомпилировать эти функции в машинные исполняемые файлы? Это связано с тем, что «контейнер» WebAssembly по-прежнему предоставляет множество ценных сервисов.

Во-первых, веб-сборкаИзолируйте функции на уровне выполнения. Ошибки в коде или проблемы безопасности памяти не распространяются за пределы среды выполнения WebAssembly. вместе сцепочка поставок программного обеспеченияПоскольку с каждым днем ​​все сложнее, важно запускать код в контейнерах, чтобы предотвратить несанкционированный доступ к вашим данным через зависимые библиотеки.

Во-вторых, байт-код WebAssemblyпортативный. Разработчикам нужно выполнить сборку только один раз, и им не нужно беспокоиться о будущих изменениях или обновлениях базового бессерверного контейнера Vercel (ОС и аппаратного обеспечения). Это также позволяет разработчикам повторно использовать одни и те же функции WebAssembly в аналогичных средах хостинга, таких какБессерверные функции Tencentили в общедоступном облаке, напримерПоток данных, как YoMoв рамке.

наконец,WasmEdge Tensorflow APIОбеспечивает наиболее совместимый с Rust способ выполнения моделей Tensorflow. WasmEdge устанавливает правильное сочетание зависимостей Tensorflow и предоставляет разработчикам унифицированный API.

Концепций и объяснений сказано много, куй железо, пока горячо, давайте взглянем на пример приложения!

Готов к работе

Поскольку наша демонстрационная функция WebAssembly написана на Rust, вам потребуетсяКомпилятор ржавчины. Обязательно установите следующим образомwasm32-wasiЦель компилятора для создания байт-кода WebAssembly.

$ rustup target add wasm32-wasi

Передняя часть демонстрационного приложенияNext.jsНаписано и развернуто на Vercel. Мы предполагаем, что у вас уже есть базовые знания по использованию Vercel.

Пример 1: Обработка изображения

Наше первое демонстрационное приложение позволяет пользователям загружать изображение, а затем вызывает бессерверную функцию, чтобы превратить его в черно-белое изображение. Прежде чем начать, вы можете попробовать это, развернутое на Vercel.demo.

первая вилкаРепозиторий GitHub для демо-приложения. Развертывайте приложения на Vercel просто изVercel for GitHubточка страницыGitHub repoимпорт.

Содержимое этого репозитория GitHub представляет собой стандартное приложение Next.js для платформы Vercel. Его внутренняя бессерверная функция находится в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();
}

используя ржавчинуcargoИнструменты для создания программ на Rust в виде байт-кода WebAssembly или собственного кода.

$ cd api/functions/image-grayscale/
$ cargo build --release --target wasm32-wasi

Скопируйте артефакты сборки вapiпапка.

$ cp target/wasm32-wasi/release/grayscale.wasm ../../

Vercel запускается при настройке бессерверной средыapi/pre.sh. Среда выполнения WasmEdge установлена, а программа байт-кода WebAssembly скомпилирована в собственныйsoбиблиотека для более быстрого выполнения.

api/hello.jsФайл соответствует бессерверной спецификации Vercel. Он загружает среду выполнения WasmEdge, запускает скомпилированную программу WebAssembly в WasmEdge и передает данные загруженного изображения через 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-0.8.1-Linux/bin/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('');
}

Закончено. Затем разверните репо наVercel, вы получаете приложение Jamstack. Приложение имеет высокопроизводительный бессерверный сервер на основе Rust и WebAssembly.

Пример 2: вывод ИИ

второе демоПриложение позволяет пользователю загрузить изображение, а затем вызвать бессерверную функцию для определения основного объекта на изображении.

Он находится в том же репозитории GitHub, что и предыдущий пример, но вtensorflowветвь. Примечание: этоGitHub repoПри импорте на веб-сайт Vercel Vercel создастURL-адрес предварительного просмотра.tensorflowФилиал будет иметь собственный URL-адрес развертывания.

Бэкэнд-бессерверные функции для классификации изображений расположены по адресуtensorflowв филиалеapi/functions/image-classificationпапка.src/main.rsФайл содержит исходный код программы Rust. Rust программы отSTDINПрочитайте данные изображения, затем выведите текстовый вывод вSTDOUT. Он использует API WasmEdge Tensorflow для выполнения выводов ИИ.

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-grayscale/
$ cargo build --release --target wasm32-wasi

Скопируйте артефакты сборки вapiпапка

$ cp target/wasm32-wasi/release/classify.wasm ../../

такой же,api/pre.shСценарий устанавливает среду выполнения WasmEdge и ее зависимости Tensorflow в этом приложении. Он также будет развернутclassify.wasmПрограмма байт-кода компилируется вclassify.soРодная общая библиотека.

api/hello.jsФайл соответствует бессерверной спецификации Vercel. Он загружает среду выполнения WasmEdge, запускает скомпилированную программу WebAssembly в WasmEdge и передает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('');
}

Теперь вы можетеРазверните разветвленное репо на Vercel, вы получаете приложение Jamstack, которое распознает объекты.

Просто измените функцию Rust в шаблоне, и вы сможете развернуть собственное высокопроизводительное приложение Jamstack!

Перспектива

Запуск WasmEdge из текущего бессерверного контейнера Vercel — это простой способ добавить высокопроизводительные функции в ваше приложение Vercel.

Если вы разработали интересные функции или приложения Vercel с помощью WasmEdge, вы можете добавить WeChat h0923xw, чтобы получить небольшой подарок.

В дальнейшем лучшим подходом будет использование самого WasmEdge в качестве контейнера, а не запуск WasmEdge с Docker и Node.js, как это происходит сегодня. Таким образом, мы можем более эффективно запускать бессерверные функции. WasmEdge имеетСовместимость с инструментами Docker. Если вы заинтересованы в том, чтобы присоединиться к WasmEdge и CNCF в этой захватывающей работе,Добро пожаловать на наш канал.