架构实战——Dapr 的轻量级、安全、便携和高性能运行时( 二 )

  • image-api-go 项目提供了一个 WasmEdge 微服务来使用 分类 功能识别和分类输入图像上的 对象 。它演示了用于 Dapr 和 WasmEdge 的 Go SDK 的使用 。

  • 架构实战——Dapr 的轻量级、安全、便携和高性能运行时

    文章插图
     
    图 2. 演示应用程序中的 Dapr sidecar 微服务 。
    您可以按照 README 中的说明启动 sidecar 服务 。以下是构建 WebAssembly 功能和启动 3 个 sidecar 服务的命令 。
    # Build the classify and grayscale WebAssembly functions, and deploy them to the sidecar projects$ cd functions/grayscale$ ./build.sh$ cd ../../$ cd functions/classify$ ./build.sh$ cd ../../# Build and start the web service for the Application UI$ cd web-port$ go build$ ./run_web.sh$ cd ../# Build and start the microservice for image processing (grayscale)$ cd image-api-rs$ cargo build$ ./run_api_rs.sh$ cd ../# Build and start the microservice for tensorflow-based image classification$ cd image-api-go$ go build --tags "tensorflow image"$ ./run_api_go.sh$ cd ../最后,您应该能够在浏览器中看到 Web UI 。
    架构实战——Dapr 的轻量级、安全、便携和高性能运行时

    文章插图
     
    图 3. 运行中的演示应用程序 。
    两个 WebAssembly 函数我们有两个用 Rust 编写并编译成 WebAssembly 的函数 。它们部署在 sidecar 微服务中,以执行图像处理和分类的实际工作 。
    虽然我们的示例 WebAssembly 函数是用 Rust 编写的,但您可以将用 C/C++、Swift、Kotlin 和 AssemblyScript 编写的函数编译为 WebAssembly 。WasmEdge 还支持用 JavaScript 和 DSL 编写的函数 。
    grayscale函数是一个 Rust 程序,它读取图像数据 STDIN 并将灰度图像写入 STDOUT.
    use image::{ImageFormat, ImageOutputFormat};use std::io::{self, Read, Write};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();}我们使用 rustwasmc 构建它,然后将其复制到 image-api-rs sidecar 。
    $ cd functions/grayscale$ rustup override set 1.50.0$ rustwasmcbuild --enable-ext$ cp ./pkg/grayscale.wasm ../../image-api-rs/lib分类函数是一个 Rust 函数,它将图像数据的 字节数组作为输入,并返回一个用于分类的字符串 。它使用 WasmEdge TensorFlow API 。
    use wasmedge_tensorflow_interface;pub fn infer_internal(image_data: &[u8]) -> String {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");let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(image_data, 224, 224);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");// ... Map the probabilities in res_vec to text labels in the labels file ...if max_value > 50 {format!("It {} a <a href=https://www.isolves.com/it/cxkf/jiagou/2022-06-08/'https://www.google.com/search?q={}'>{} in the picture",confidence.to_string(),class_name,class_name)} else {format!("It does not appears to be any food item in the picture.")}}我们使用 rustwasmc 构建它,然后将其复制到 image-api-go sidecar 。
    $ cd functions/classify$ rustup override set 1.50.0$ rustwasmcbuild --enable-ext$ cp ./pkg/classify_bg.wasm ../../image-api-go/lib/classify_bg.wasm在接下来的三个部分中,我们将研究这三个 sidecar 服务 。
    图像处理边车image-api-rs sidecar 应用程序是用 Rust 编写的 。它应该已经从上一步安装了 WebAssembly 函数 lib/grayscale.wasm 。请参考 functions/bin/install.sh 脚本来安装 WasmEdge 运行时二进制文件 lib/wasmedge-tensorflow-lite 及其依赖项 。
    Sidecar 微服务运行一个基于 Tokio 的事件循环,该循环在路径上侦听传入的 HTTP 请求 /api/image 。
    #[tokio::main]pub async fn run_server(port: u16) {pretty_env_logger::init();let home = warp::get().map(warp::reply);let image = warp::post().and(warp::path("api")).and(warp::path("image")).and(warp::body::bytes()).map(|bytes: bytes::Bytes| {let v: Vec<u8> = bytes.iter().map(|&x| x).collect();let res = image_process(&v);Ok(Box::new(res))});let routes = home.or(image);let routes = routes.with(warp::cors().allow_any_origin());let log = warp::log("dapr_wasm");let routes = routes.with(log);warp::serve(routes).run((Ipv4Addr::UNSPECIFIED, port)).await}


    推荐阅读