边缘云微服务 – 如何使用 WasmEdge 和 Rust 构建高性能和安全的应用程序





5.00/5 (1投票)
如何在 WebAssembly 沙箱中创建轻量级、高性能的 Web 服务,然后免费将其部署到边缘云提供商 fly.io。
边缘云允许开发人员将微服务(即细粒度的 Web 服务)部署在离用户更近的地方。这可以提供更好的用户体验(响应速度极快)、安全性和高可用性。
它还利用本地甚至私有数据中心、CDN 网络和电信数据中心(例如 5G MEC)来提供计算服务。
边缘云的成功案例包括 Cloudflare、Fastly、Akamai、fly.io、Vercel、Netlify 等等。
但与大型公共云相比,边缘云也是一个资源受限的环境。如果边缘微服务本身运行缓慢、臃肿或不安全,那么将它们部署在边缘云的整个目的就无法实现。
在本文中,我将向您展示如何在 WebAssembly 沙箱中创建轻量级、高性能的 Web 服务,然后免费将其部署到边缘云提供商 fly.io。
Fly.io 是边缘云 VM 服务领域的领导者。它在全球各地设有边缘数据中心。 fly.io 的 VM 支持应用服务器、数据库,在本例中,还支持微服务的轻量级运行时。
我将使用 WasmEdge Runtime 作为这些微服务的安全沙箱。WasmEdge 是一个专门为云原生服务优化的 WebAssembly 运行时。
我们将使用 Rust 或 JavaScript 编写的微服务应用程序打包到 基于 WasmEdge 的 Docker 镜像中。
这种方法有几个引人注目的优点:
- WasmEdge 以接近原生速度运行沙箱化应用程序。根据一项同行评审的研究,WasmEdge 运行 Rust 程序的速度几乎与 Linux 运行原生机器代码的速度相同。
- WasmEdge 是一个高度安全的运行时。它保护您的应用程序免受外部和内部威胁。
- 与常规 Linux OS 运行时相比,WasmEdge 运行时的攻击面大大减小。
- 由于 WebAssembly 沙箱只能访问明确声明的功能,因此软件供应链攻击的风险大大降低。
- WasmEdge 提供了一个完整且可移植的应用程序运行时环境,其内存占用量仅为标准 Linux OS 运行时镜像的 1/10。
- WasmEdge 运行时是跨平台的。这意味着开发和部署机器不必相同。一旦创建了 WasmEdge 应用程序,您就可以将其部署到任何支持 WasmEdge 的地方,包括 fly.io 基础架构。
如果应用程序很复杂,性能优势会得到放大。例如,WasmEdge AI 推理应用程序将不需要安装 Python。WasmEdge node.js 应用程序将不需要安装 Node.js 和 v8。
在本文的其余部分,我将演示如何运行:
- 一个异步 HTTP 服务器(用 Rust 编写)
- 一个非常快速的图像分类 Web 服务(用 Rust 编写),以及
- 一个 Node.js Web 服务器
- 带有数据库连接的状态微服务
所有这些都在 WasmEdge 中运行快速且安全,同时消耗普通 Linux 容器所需资源的 1/10。
必备组件
首先,如果您已经在系统上安装了 Docker 工具,那就太好了。如果没有,请遵循本手册的第一部分来安装 Docker。然后,我们将使用在线安装程序安装 WasmEdge、Rust 以及用于 fly.io 的 flyctl
工具。
安装 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
工具。 详细信息请参见此处。
curl -L https://fly.io/install.sh | sh
安装 flyctl
后,请按照说明在 fly.io 注册免费帐户。现在,您可以将 Web 服务部署到边缘云了!
Rust 中的简单微服务
我们的第一个例子是一个简单的 Rust HTTP 服务。它演示了一个现代 Web 应用程序,可以扩展以支持任意复杂的业务逻辑。
该微服务基于流行的 tokio 和 hyper crate,速度快、异步(非阻塞),并且对开发人员来说非常容易创建。
完全静态链接的 WasmEdge 镜像仅为 4MB,而基础 Linux 镜像为 40MB。这足以运行用 Rust 的 tokio 和 hyper 框架编写的异步 HTTP 服务。
运行以下两个 CLI 命令,以从我们为 WasmEdge 准备的精简 Docker 镜像创建并部署一个 fly.io 应用。
$ flyctl launch --image juntaoyuan/flyio-echo
$ flyctl deploy
就是这样!您可以使用 curl
命令测试已部署的 Web 服务是否正常工作。它会回显您发送给它的任何数据。
$ curl https://proud-sunset-3795.fly.dev/echo -d "Hello WasmEdge on fly.io!"
Hello WasmEdge on fly.io!
juntaoyuan/flyio-echo
Docker 镜像的 Dockerfile 包含 WasmEdge 运行时和自定义 Web 应用程序 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 推理微服务
在本例中,我们将创建一个用于图像分类的 Web 服务。它通过 Tensorflow Lite 模型处理上传的图像。
我们不创建复杂的(且臃肿的)Python 程序,而是使用 WasmEdge 的 Rust API 来访问 Tensorflow,从而以完整的原生机器代码速度运行推理任务(例如,如果可用,则利用 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 服务是否正常工作。它会返回带有置信度的图像分类结果。
$ 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
命令测试已部署的 Web 服务是否正常工作。它会回显您发送给它的任何数据。
$ 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 镜像的 Dockerfile 包含 WasmEdge 运行时、QuickJS 运行时 wasmedge_quickjs.wasm
、Node.js 模块以及 Web 服务应用程序 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 API 来创建一个异步 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 SDK 封装到 JavaScript API 中,以便 JavaScript 开发人员可以轻松创建 AI 推理应用程序。
边缘状态微服务
使用 WasmEdge,还可以创建由数据库支持的状态微服务。 此 GitHub 仓库包含 WasmEdge 应用程序中基于 tokio 的非阻塞数据库客户端的示例。
- MySQL 客户端允许 WasmEdge 应用程序访问大多数云数据库。
- anna-rs 项目是一个边缘原生的 KV 存储,在边缘节点上具有可调的同步和一致性级别。WasmEdge 应用程序可以使用 anna-rs 作为边缘缓存或数据库。
您现在可以使用 WasmEdge SDK 和运行时在边缘云上构建各种 Web 服务。迫不及待地想看到您的作品!
历史
- 2023 年 1 月 5 日:初始版本