最近看到《用 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
从上面的例子可以看出:
- 开发者只需要写好事件处理的函数,修改配置文件,确认部署即可,而不需要了解服务器的基础架构,甚至也不需要了解代码实际部署在哪个 Web 框架。
- 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