如何利用 WasmEdge 和 Rust 構建高性能和安全的應用程序

邊緣雲允許開發者在靠近用戶的地方部署微服務(即細粒度的網絡服務)。這爲他們提供了更好的用戶體驗(和非常快的響應時間)、安全和高可用性。

它還利用本地甚至私人數據中心、CDN 網絡和電信數據中心(例如 5G MECs)來提供計算服務。

邊緣雲的成功例子包括 Cloudflare、Fastly、Akamai、fly.io、Vercel、Netlify 等等。

但與大型公有云相比,邊緣雲也是一個資源受限的環境。如果邊緣微服務本身很慢或很臃腫或不安全,它們將違背在邊緣雲上部署的整個目的。

在這篇文章中,我將向你展示如何在 WebAssembly 沙盒中創建輕量級和高性能的 Web 服務,然後將它們免費部署在邊緣雲提供商 fly.io。

Fly.io 是一家在邊緣雲上提供虛擬機服務的領先供應商。它在世界各地都有邊緣數據中心。fly.io 的虛擬機支持應用服務器、數據庫,以及在我們的案例中支持微服務的輕量級運行時。

我將使用 WasmEdge Runtime 作爲這些微服務的安全沙盒。WasmEdge 是一個專門爲雲原生服務優化的 WebAssembly 運行時。

我們將把用 Rust 或 JavaScript 編寫的微服務應用打包在基於 WasmEdge 的 Docker 鏡像中。

這種方法有幾個引人注目的優勢:

如果應用程序很複雜,則性能優勢會被放大。例如,WasmEdge 上的 AI 人工智能應用程序不需要安裝 Python。WasmEdge 上的 node.js 應用程序不需要安裝 Node.js 和 v8。

在本文的其餘部分,我將演示如何運行:

所有這些都在 WasmEdge 中快速、安全地運行,而消耗的資源是普通 Linux 容器的 1/10。

環境準備

首先,如果你的系統中已經安裝了 Docker 工具,那就太好了。如果沒有,請按照本手冊的第一節現在就安裝 Docker。然後我們將使用在線安裝程序來安裝 WasmEdge、Rust 和 [fly.io] 的 flyctl 工具(http://fly.io)。

安裝 WasmEdge。詳見這裏。

curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -e all

安裝 Rust。詳見這裏。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

爲 fly.io 安裝 flyctl 工具(http://fly.io )。詳見這裏。

curl -L https://fly.io/install.sh | sh

一旦你安裝了flyctl,按照指示在 fly.io 上註冊一個免費賬戶。現在你已經準備好在邊緣雲上部署網絡服務了。

用 Rust 實現的一個簡單的微服務

我們的第一個例子是一個用 Rust 編寫的簡單 HTTP 服務。它展示了一個現代網絡應用,可以擴展到支持任意複雜的業務邏輯。

基於流行的 tokio 和 hyper crates,這個微服務是快速的、異步的(非阻塞的),並且對開發者來說非常容易創建。

完全靜態鏈接的 WasmEdge 鏡像只有 4MB,而基本的 Linux 鏡像是 40MB。這足以運行一個用 Rust 的 tokio 和 hyper 框架編寫的異步 HTTP 服務。

運行以下兩個 CLI 命令,從我們爲 WasmEdge 設計的超薄(slim) Docker 鏡像中創建並部署一個 fly.io 應用程序。

$ flyctl launch --image juntaoyuan/flyio-echo
$ flyctl deploy

爲什麼這樣做?你可以使用 curl 命令來測試所部署的網絡服務是否真的工作。無論你向它發佈什麼數據,它都會回顯(echoes back)出來。

$ curl https://proud-sunset-3795.fly.dev/echo -d "Hello WasmEdge on fly.io!"
Hello WasmEdge on fly.io!

juntaoyuan/flyio-echo Docker 鏡像的 Docker 文件包含 WasmEdge 運行時的完整包和自定義網絡應用wasmedge_hyper_server.wasm

FROM wasmedge/slim-runtime:0.11.0
ADD wasmedge_hyper_server.wasm /
CMD ["wasmedge""--dir"".:/""/wasmedge_hyper_server.wasm"]

構建wasmedge_hyper_server.wasm應用程序的 Rust 源代碼項目,可在 GitHub 上找到。它使用 tokio API 來啓動一個 HTTP 服務器。

當服務器收到一個請求時,它委託給 echo() 函數來異步處理該請求。這使得微服務可以接受並處理多個併發的 HTTP 請求。

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let addr = SocketAddr::from(([0, 0, 0, 0], 8080));

    let listener = TcpListener::bind(addr).await?;
    println!("Listening on http://{}", addr);
    loop {
        let (stream, _) = listener.accept().await?;

        tokio::task::spawn(async move {
            if let Err(err) = Http::new().serve_connection(stream, service_fn(echo)).await {
                println!("Error serving connection: {:?}", err);
            }
        });
    }
}

異步的 echo() 函數如下。它利用 hyper 提供的 HTTP API 來解析請求並生成響應。這裏,響應只是請求數據體。

async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
    match (req.method(), req.uri().path()) {
        ... ...
        (&Method::POST, "/echo") => Ok(Response::new(req.into_body())),
        ... ...

        // Return the 404 Not Found for other routes.
        _ ={
            let mut not_found = Response::default();
            *not_found.status_mut() = StatusCode::NOT_FOUND;
            Ok(not_found)
        }
    }
}

現在,讓我們在基本的微服務中添加一些令人印象深刻的東西吧!

用 Rust 實現的 AI 人工智能的微服務

在這個例子中,我們將創建一個用於圖像分類的網絡服務。它通過一個 Tensorflow Lite 模型處理上傳的圖像。

我們將使用 WasmEdge 的 Rust API 來訪問 Tensorflow,而不是創建一個複雜(和臃腫)的 Python 程序,它以完整的本地機器碼速度運行推理任務(例如,如果有的話,利用 GPU 硬件)。

通過 WASI-NN 標準,WasmEdge 的 Rust API 可以使用 Tensorflow、PyTorch、OpenVINO 和其他 AI 框架中的 AI 模型。

對於包含完整 Tensorflow Lite 依賴項的 AI 推理應用程序,WasmEdge 佔用空間小於 115MB。相比之下,標準 Tensorflow Linux 映像超過 400MB。

運行以下兩個 CLI 命令,從我們用於 WasmEdge + Tensorflow 的超薄 Docker 鏡像創建並部署一個 fly.io 應用程序。

$ flyctl launch --image juntaoyuan/flyio-classify
$ flyctl deploy

就是這樣!你可以使用 curl 命令來測試部署的 Web 服務是否真正起作用。它返回具有置信度(confidence level)的圖像分類結果。

$ curl https://silent-glade-6853.fly.dev/classify -X POST --data-binary "@grace_hopper.jpg"
military uniform is detected with 206/255 confidence

juntaoyuan/flyio-classify Docker 鏡像的 Dockerfile 包含 WasmEdge 運行時的完整包、整個 Tensorflow 庫及其依賴項,以及自定義 Web 應用程序 wasmedge_hyper_server_tflite.wasm

FROM wasmedge/slim-tf:0.11.0
ADD wasmedge_hyper_server_tflite.wasm /
CMD ["wasmedge-tensorflow-lite""--dir"".:/""/wasmedge_hyper_server_tflite.wasm"]

構建wasmedge_hyper_server_tflite.wasm應用程序的 Rust 源代碼項目,可在 GitHub 上找到。基於 tokio 的異步 HTTP 服務器在異步main()函數中,與前面的例子一樣。

classify()函數處理請求中的圖像數據,將圖像變成張量,運行 Tensorflow 模型,然後將返回值(在張量中)變成文本標籤和可能分類的概率。

async fn classify(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
    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");
    match (req.method(), req.uri().path()) {

        (&Method::POST, "/classify") ={
            let buf = hyper::body::to_bytes(req.into_body()).await?;
            let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(&buf, 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");
            ... ...

            let mut label_lines = labels.lines();
            for _i in 0..max_index {
              label_lines.next();
            }
            let class_name = label_lines.next().unwrap().to_string();

            Ok(Response::new(Body::from(format!("{} is detected with {}/255 confidence", class_name, max_value))))
        }

        // Return the 404 Not Found for other routes.
        _ ={
            let mut not_found = Response::default();
            *not_found.status_mut() = StatusCode::NOT_FOUND;
            Ok(not_found)
        }
    }
}

在本文的最後一節,我們將討論如何爲 Rust 微服務添加更多的功能,如數據庫客戶端和 Web 服務客戶端。

用 Node.js 實現的一個簡單的微服務

雖然基於 Rust 的微服務是輕量和快速的,但不是每個人都是 Rust 開發者。

如果你更熟悉 JavaScript,你仍然可以在邊緣雲中利用 WasmEdge 的安全性、性能、佔用空間小和可移植性。具體來說,你可以使用 Node.js API 爲 WasmEdge 創建微服務!

對於 Node.js 應用程序,WasmEdge 佔用空間小於 15MB。相比之下,標準 Node.js Linux 映像超過 150MB。

運行以下兩個 CLI 命令,從我們用於 WasmEdge + Node.js 的超薄 Docker 映像創建並部署一個 fly.io 應用程序。

$ flyctl launch --image juntaoyuan/flyio-nodejs-echo
$ flyctl deploy

這就是了!你可以使用 curl 命令來測試所部署的網絡服務是否真的工作。無論你向它發佈什麼數據,它都會回顯出來。

$ curl https://solitary-snowflake-1159.fly.dev -d "Hello WasmEdge for Node.js on fly.io!"
Hello WasmEdge for Node.js on fly.io!

juntaoyuan/flyio-nodejs-echo Docker 鏡像的 Docker 文件包含 WasmEdge 運行時、QuickJS 運行時wasmedge_quickjs.wasm、Node.js 模塊和網絡服務應用程序node_echo.js的完整包。

FROM wasmedge/slim-runtime:0.11.0
ADD wasmedge_quickjs.wasm /
ADD node_echo.js /
ADD modules /modules
CMD ["wasmedge""--dir"".:/""/wasmedge_quickjs.wasm""node_echo.js"]

node_echo.js應用程序的完整 JavaScript 源代碼如下。你可以清楚地看到,它只是使用標準的 Node.js APIs 來創建一個異步的 HTTP 服務器,回顯 HTTP 請求體。

import { createServer, request, fetch } from 'http';

createServer((req, resp) ={
  req.on('data'(body) ={
    resp.end(body)
  })
}).listen(8080, () ={
  print('listen 8080 ...\n');
})

WasmEdge 的 QuickJS 引擎不僅提供 Node.js 支持,還提供 Tensorflow 推理支持。我們將 Rust Tensorflow 和 WASI-NN SDKs 包裝成 JavaScript APIs,以便 JavaScript 開發人員可以輕鬆創建 AI 人工智能應用程序。

在邊緣部署的有狀態的微服務

使用 WasmEdge,也可以創建由數據庫支持的有狀態的微服務。這個 GitHub repo 包含了 WasmEdge 應用程序中基於 tokio 的非阻塞數據庫客戶端的例子。

你現在可以使用 WasmEdge SDK 和運行時在邊緣雲上構建各種 Web 服務。期待很快可以看到你的作品!


原文鏈接:https://www.freecodecamp.org/news/edge-cloud-microservices-with-wasmedge-and-rust/

作者:Michael Yuan

譯者:luojiyin

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/JuL2rHOzlagji-O09JjhCA