边缘云上的高性能且安全的微服务

Posted serverless 技术社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了边缘云上的高性能且安全的微服务相关的知识,希望对你有一定的参考价值。

边缘云让开发者能够在靠近用户的地方部署微服务(即细颗粒度的 Web 服务),从而实现更好的用户体验(即非常快的响应时间)、绝佳的安全性以及高可用性。 边缘云利用本地乃至私有的数据中心、CDN 网络和电信数据中心(例如 5G MEC)来提供计算服务。 边缘云的成功案例包括 Cloudflare、Fastly、Akamai、fly.io、Vercel、Netlify 等。

但是,与大型公共云相比,边缘云是一个资源受限的环境。 如果边缘微服务本身运行缓慢、臃肿或不安全,将导致在边缘云上部署的全部优势丧失殆尽。

本文将展示如何创建轻量级和高性能的 Web 服务,然后将其免费部署到边缘云提供商 fly.io 上。

Fly.io 是一个领先的边缘云 VM 服务提供商,它在世界各地都有边缘数据中心。fly.io VM 支持应用程序服务器、数据库以及我们这种微服务的轻量级 runtime。

我将使用 WasmEdge runtime 作为这些微服务的安全沙箱。 WasmEdge 是专门针对云原生服务优化的 WebAssembly runtime。我们将在基于 WasmEdge 的 Docker Images 中打包用 Rust 或 javascript 编写的微服务应用程序。这种方法有几种巨大优势。

  • WasmEdge 以接近原生的速度运行沙盒应用。根据一项经过同行评审的研究,WasmEdge 能够以近似 Linux 运行原生机器代码的速度运行 Rust 程序。
  • WasmEdge 是一个高度安全的 runtime。它可以保护你的应用程序免受外部和内部攻击威胁。
    • WasmEdge runtime 受攻击的脆弱点,相比常规 Linux OS runtime 大大减少。
    • 软件供应链攻击的风险大大降低了,因为 WebAssembly 沙箱仅允许明确声明的访问。
  • WasmEdge 在内存足迹上提供了一个完整的可移植应用程序 runtime 环境,仅是标准Linux OS runtime 镜像的1/10。
  • WasmEdge runtime 是跨平台的。这意味着机器的开发和部署不必相同。一旦创建了一个 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.io 安装 flyctl 工具。此处查看详细信息

`curl -L `[`https://fly.io/install.sh`](https://fly.io/install.sh)` | sh`

安装好了 flyctl 之后, 请按照指引在 fly.io.上注册免费帐户。现在就可以在边缘云上部署 Web 服务了!

Rust 写的一个简单的微服务

我们的第一个示例是用 Rust 编写的简单 HTTP 服务。它演示了一个现代的 Web 应用程序,可以扩展以支持任意复杂的业务逻辑。基于流行的 Tokio 和 Hyper Crate,这个微服务是非常快、异步的(non-blocking),并且对于开发者来说非常容易创建。

完全静态链接的 WasmEdge 镜像只有 4MB(相比之下基础 Linux 镜像则为 40MB)。这足以运行用 Rust 的 tokio 和 hyper 框架编写的异步 HTTP 服务。

运行以下两个 CLI 命令,然后从 WasmEdge 的 Slim 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 镜像的 dockerfile 包含 WasmEdge runtime 和自定义的 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 源代码项目在这里。它使用 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 模型处理上传的图片。我们将使用 WasmEdge 的 Rust API 来访问 Tensorflow,而不是创建一个复杂(且臃肿)的 Python 程序,它以本机机器代码速度运行推理任务(例如,如果有 GPU ,也可以在 GPU 硬件上运行)。通过 WASI-NN 标准,WasmEdge 的 Rust API 可以与 Tensorflow、PyTorch、OpenVINO 和其他 AI 框架中的 AI 模型一起使用。

对于包含完整 Tensorflow Lite 依赖项的 AI 推理应用程序,WasmEdge 占用空间小于 115MB。 相比之下,标准 Tensorflow Linux 镜像超过 400MB。

从 WasmEdge + Tensorflow 的 slim Docker 镜像开始,运行以下两个 CLI 命令来创建并部署一个 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 runtime 的完整包、整个 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 源代码项目在这里。 基于 tokio 的异步 HTTP 服务器位于 async main() 函数中,如上一个示例所示。 classify() 函数处理请求中的图片数据,将图片转换为 tensor,运行 Tensorflow 模型,然后将返回值(在一个 tensor 中)转换为文本标签和所识别出内容的概率。

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。

从 WasmEdge + node.js 的 slim Docker 镜像开始,运行以下两个 CLI 命令,创建并部署一个 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 runtime 、QuickJS runtime 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 的 non-blocking 数据库客户端的示例。

  • MySQL client 允许 WasmEdge 应用程序访问大多数云数据库。
  • WasmEdge 应用程序可以使用anna-rs 作为边缘缓存或者数据库。

现在,快快使用 WasmEdge SDK 和 runtime 在边缘云上构建各种 Web 服务吧。已经迫不及待地想看到你的成果了!

阿里云上的RDS数据的本地同步

一、背景知识

数据库RDS

阿里云云数据库RDS(ApsaraDB for RDS,简称RDS)是一种稳定可靠、可弹性伸缩的在线数据库服务。基于飞天分布式系统和全SSD盘高性能存储,支持MySQL、SQL Server、PostgreSQL和PPAS(高度兼容Oracle)引擎,默认部署主备架构且提供了容灾、备份、恢复、监控、迁移等方面的全套解决方案,解决数据库运维的问题。

RDS主从架构

    应用连接RDS,流量通过SLB指向主从节点的master,所以如果我们连接RDS的账户具有REPLICATION SLAVE, REPLICATION CLIENT的权限,则就可以把主库master的产生的binlog同步到本地数据库中去,实现数据同步。

技术分享

    但是这种根据binlog文件和位点来同步RDS的数据到本地的方式非常容易导致同步中断,因为当RDS发生了主备切换(主备切换,重启,跨机迁移),本地数据库所指向RDS的binlog 位点则会发生变化(RDS主库与备库的binlog位点是不一致的),这样就会导致本地数据库与RDS的数据复制同步中断。

技术分享

    在RDS 5.6的版本中主备同步使用新复制方式GTID,RDS的主备具有相同的GTID,那么如果主备发生切换,重启或者迁移,主备的GTID是不会发生变化,那么ECS和RDS的同步链路则不会发生中断,所以如果要将RDS的数据同步到本地,则需要将RDS升级到5.6的版本。

GTID简介

    Global Transaction ID,全局事务ID,在整个事务架构中每一个事务ID号是全局唯一的,不止是在一个节点上而是整个主从复制架构中每任何两个事务的ID号都不会相同。


  • 全局事务ID是怎么生成的?


简单来讲是由mysql服务器自动管理的,在mysql5.6以后每一个mysql服务器都有一个全局唯一的ID号叫做uuid,通用唯一识别码 (Universally Unique Identifier),而GTID就是由当前节点的UUID(一个128位的随机数)和为当前节点生成的随机数(TID)组成的,因此只要UUID不同再在此基础上保证事务ID不同就保证全局不一样了。


  • 全局事务ID有何用处?


简单来讲GTID能够保证让一个从服务器到其他的从服务器那里实现数据复制而且能够实现数据整合的。GTID在分布式架构中可以保证数据的一致性。从而也实现了mysql的高可用性。

    默认情况下将一个事务记录进二进制文件时将首先记录它的GTID而且GTID和事务相关信息一并要发送给从服务器由从服务器在在本地应用认证但是绝对不会改变原来的事务ID号。因此在GTID的架构上就算有了N层架构,复制是N级架构、事务ID依然不会改变;有效的保证了数据的完整和安全性。

二、实验概述

    现在,越来越多的用户开始将数据存储到RDS实例中。在用户将数据上云的同时,更多的人开始关心如何将云上RDS的数据同步或保存到本地部署的MySQL数据中。因此,本实验主要实现云数据库RDS的数据同步:

1)在ECS实例上,安装并部署MySQL数据库。

2)在阿里云管理控制台,创建RDS实例的数据库账号;

3)配置RDS实例与本地部署的MySQL数据库主从关系。

4)创建RDS实例数据库,并导入测试,观察同步结果;

技术分享


以上是关于边缘云上的高性能且安全的微服务的主要内容,如果未能解决你的问题,请参考以下文章

基于Nginx搭建一个安全的快速的微服务架构

微服务举例

云原生安全从分布式追踪看云原生应用安全

将传入令牌中继到其他服务

使用 Spring Boot 的微服务中的安全问题

构建安全可靠的微服务 | Nacos 在颜铺 SaaS 平台的应用实践