最近看到《用 Serverless 架构部署 TensorFlow 模型推理函数》的活动,对 serverless 非常感兴趣,本着学习的心态初步探索两个 serverless 框架,一个是开源的 OpenFaaS,一个是腾讯云,通过实际使用和对比初步入门 Serverless。

OpenFaaS

按文档说明在 Ubuntu 20.04 上部署这个框架。

然后创建 Python 函数:

def handle(req):
    print("Hello! You said: " + req)

修改配置,这里需要写入 docker hub 的帐号。

version: 1.0
provider:
  name: openfaas
  gateway: http://127.0.0.1:8080
functions:
  pycon:
    lang: python3
    handler: ./pycon
    image: >>> dockerhub 用户名<<</pycon

OpenFaaS 提供一个叫 faas-cli 的部署工具,faas-cli 会先将镜像上传到相应的 docker hub 帐号名下,然后再下拉到 OpenFaaS 服务。

开始部署成功后在 Web 界面 127.0.0.1:8080/ui/ 看到刚才创建的函数。

测试:

╰─➤  curl localhost:8080/function/pycon -d "Hi"
Hello! You said: Hi

从上面的例子可以看出:

  1. 开发者只需要写好事件处理的函数,修改配置文件,确认部署即可,而不需要了解服务器的基础架构,甚至也不需要了解代码实际部署在哪个 Web 框架。
  2. FaaS 服务返回调用接口。

将图像识别服务部署到腾讯云

除了将 Serverless 业务构建在硬件和容器(比如,OpenFaaS 使用 docker)之外,还有一种新兴的方法: 使用特定于应用程序的虚拟机,比如 WebAssembly(Wasm)。

这个例子通过 Second State 的 Serverless Wasm 虚拟机 (SSVM), 把用 Rust 编写的图像识别业务代码最终编译成 .so 文件,通过 serverless 工具 上传到腾讯云的 FaaS 中。

根据 Second State 的 demo 部署之后,在项目根目录输入 sls deploy, 验证腾讯云帐号,100 秒左右就部署成功,查看腾讯云的控制台,可以看到刚才部署的功能。

测试:

魔改

通过魔改 Second State 的例子学习腾讯云 Serverless 的用法。

先了解 tencent-tensorflow-scf 的结构:

cos, layer, scf 三个目录都有 serveress.yml,执行 sls deploy 的时候,可以看到这三个目录的文件被打包上传。

执行 ssvmup build --enable-ext --enable-aot 生成 pkg/scf.so, 需要将它拷贝至 scf/ 目录。

scf/bootstrap 是一个脚本,运行后是一个服务进程。

核心命令如下,其中 "$_HANDLER" 是 scf.so

RESPONSE=$(LD_LIBRARY_PATH=/opt /opt/ssvm-tensorflow "$_HANDLER" <<< "$EVENT_DATA")

这就说明,我们可以在本地运行 "$_HANDLER"。我们可以先在本地调试业务功能。

首先需要编译 ssvm-tensorflow , 也可以直接下载二进制运行。

编译完之后,将 这个 demo 的代码迁移到 tencent-tensorflow-scf/src/main.rs, 实现魔改:

use std::io::{self, Read};
use ssvm_tensorflow_interface;
use serde::Deserialize;

fn search_vec(vector: &Vec<f32>, labels: &Vec<&str>, value: &f32) -> (i32, String) {
    for (i, f) in vector.iter().enumerate() {
        if f == value {
            return (i as i32, labels[i].to_owned());
        }
    }
    return (-1, "Unclassified".to_owned());
}

fn main() {
    let model_data: &[u8] = include_bytes!("mobilenet_v2_1.4_224_frozen.pb");
    let labels = include_str!("imagenet_slim_labels.txt");
    let label_lines : Vec<&str> = labels.lines().collect();


    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer).expect("Error reading from STDIN");
    let obj: FaasInput = serde_json::from_str(&buffer).unwrap();
    let img_buf = base64::decode_config(&(obj.body), base64::STANDARD).unwrap();

    let flat_img = ssvm_tensorflow_interface::load_jpg_image_to_rgb32f(&img_buf, 224, 224);

    let mut session = ssvm_tensorflow_interface::Session::new(model_data, ssvm_tensorflow_interface::ModelType::TensorFlow);
    session.add_input("input", &flat_img, &[1, 224, 224, 3])
           .add_output("MobilenetV2/Predictions/Softmax")
           .run();
    let res_vec: Vec<f32> = session.get_output("MobilenetV2/Predictions/Softmax");
    let mut sorted_vec = res_vec.clone();
    sorted_vec.sort_by(|a, b| b.partial_cmp(a).unwrap());

    let top1 = sorted_vec[0];
    let top2 = sorted_vec[1];
    let top3 = sorted_vec[2];

    let r1 = search_vec(&res_vec, &label_lines, &top1);
    let r2 = search_vec(&res_vec, &label_lines, &top2);
    let r3 = search_vec(&res_vec, &label_lines, &top3);

    println!("{}: {:.2}%\n{}: {:.2}%\n{}: {:.2}%"
        , r1.1, top1 * 100.0
        , r2.1, top2 * 100.0
        , r3.1, top3 * 100.0
        );
}

#[derive(Deserialize, Debug)]
struct FaasInput {
    body: String
}

测试:

输出排名前三的可能结果。

tomato.json 用于模拟请求数据,将图片数据 base64 之后放在 "body" 后面。

最后重新 sls deploy 部署上线:

总结

本文通过 OpenFaaS 和腾讯云 Serverless 两种服务,初步了解了将业务部署到云平台的过程。通过 FaaS 服务商提供的工具,用户可以避免直接操作 docker, 或设置脚本运行环境变量等不重要的细节,从而将注意力集中在业务开发上。

One More Thing

立即体验腾讯云 Serverless Demo,领取 Serverless 新用户礼包 👉 serverless/start

03-05 16:22