如何利用 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 以接近原生的速度運行沙盒應用程序。根據一項同行評議的研究,WasmEdge 運行 Rust 程序的速度幾乎與 Linux 運行本地機器代碼的速度相同。
-
WasmEdge 是一個高度安全的運行時。它可以保護你的應用程序免受外部和內部威脅。
-
WasmEdge 運行時的攻擊面比普通的 Linux 操作系統運行時大大減少。
-
由於 WebAssembly 沙盒只能訪問明確聲明的資源,軟件供應鏈攻擊的風險大大降低。
-
WasmEdge 提供了一個完整的和可移植的應用程序運行環境,其內存佔用只有標準 Linux 操作系統運行時鏡像的 1/10。
-
WasmEdge 運行時是跨平臺的。這意味着開發和部署的機器不必是相同的。而一旦你創建了一個 WasmEdge 應用程序,你可以將它部署到任何支持 WasmEdge 的地方,包括 fly.io 基礎設施。
如果應用程序很複雜,則性能優勢會被放大。例如,WasmEdge 上的 AI 人工智能應用程序不需要安裝 Python。WasmEdge 上的 node.js 應用程序不需要安裝 Node.js 和 v8。
在本文的其餘部分,我將演示如何運行:
-
一個異步的 HTTP 服務器(用 Rust 實現)
-
一個非常快速的圖像分類網絡服務(用 Rust 實現),以及
-
一個 node.JS 網絡服務器
-
具有數據庫連接的有狀態微服務
所有這些都在 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 的非阻塞數據庫客戶端的例子。
-
MySQL 客戶端
允許 WasmEdge 應用程序訪問大多數雲數據庫。
-
anna-rs 項目
是一個邊緣原生 KV 存儲,在邊緣節點上具有可調整的同步和一致性級別。WasmEdge 應用程序
可以使用 anna-rs
作爲邊緣緩存或數據庫。
你現在可以使用 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