65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2023 年 1 月 5 日

CPOL

7分钟阅读

viewsIcon

12968

如何在 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.ioflyctl 工具。

安装 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.ioflyctl 工具。 详细信息请参见此处

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 日:初始版本
© . All rights reserved.