有贊算法平臺之模型部署演進
文|三餘
一、前言
模型部署作爲算法工程落地的最後一公里,其天然對算法團隊而言具有較高的複雜性,不僅要考慮如何高效地部署、管理不同框架模型,還需要考慮分佈式服務的負載均衡、故障容錯、可擴展性、資源隔離、限流、核心指標監控等問題。這些都極大的依賴於工程團隊的能力,不是算法團隊的強項,如何解決這最後一公里,讓焦點聚焦在模型開發上,是模型部署服務模塊需要解決的問題。
二、原有架構
2.1 架構設計
在有贊算法平臺 Sunfish 包含算法訓練和模型部署兩部分, 模型部署的模塊稱爲 ABox(小盒子)。
ABox 主要提供將模型部署爲在線服務的功能, 主要包含以下功能:
- 提供 tensorflow 模型的服務加載和版本管理、彈性部署
- 提供 tensorflow 模型和其他模型服務(自己部署在額外服務器上)的路由管理
- 提供模型輸入和輸出的自定義處理邏輯執行
- 提供服務主機的負載均衡管理
5. 收集的 Metric 寫入上報到 kafka,通過 druid 做監控,並提供指標界面查詢
其整體的架構設計如下圖所示分爲 3 個模塊: master、 worker 和 manager, 各自主要職責爲:
master:
-
業務請求的路由
根據 zookeeper 上的動態路由選擇將請求直接路由給可以訪問的服務(這裏包括 TF-Serving 服務和第三方註冊 REST 服務,多個服務之間採用輪詢的方式), 請求不會經過 worker。 -
自定義 jar 包(udl: user defined lib)執行
在模型預測前和預測後可以加載自定義處理邏輯,可以對模型的輸入數據和輸出數據進行預處理
worker:
-
註冊本機信息,負責上報心跳給 manager, 心跳包含本機上的算法服務的健康狀態
-
負責算法模型的本地拉取, 由 tf-serving 服務加載模型
manager:
-
負責服務器(master 和 worker)的註冊和下線
-
負責算法和模型的創建
-
提供 udl 的更新接口
-
提供集羣、業務組管理的接口
-
提供模型的部署和上下線功能
-
提供第三方算法的註冊和上下線功能
2.2 痛點問題
基於以上架構,ABox 能較好的支持 tensorflow cpu 模型的部署,但存在以下問題:
痛點 1 運維投入大
-
擴縮容需要人工調用接口
-
模型服務最多實例個數取決於 worker 節點個數, 橫向擴容需要增加機器
-
除 tensorflow 模型部署, 其他需要人工調用接口註冊 URL 到 master 來提供路由能力
-
tfserving 採用容器化部署,模型加載過多易 OOM,無法自動拉起
痛點 2 負載不均衡
- 模型按照一定的資源調度策略分佈在各個 worker 節點上,各 worker 節點資源使用容易不均衡
痛點 3 資源未隔離
- 熱點模型佔用大量的 CPU / 內存,容易影響其他模型服務
痛點 4 缺乏通用性
-
模型服務無法統一管理, tensorflow 模型和其他框架模型管理割裂
-
沒有 GPU 模型服務部署功能
三、改造升級
3.1 seldon 介紹
基於前述問題,爲了統一不同框架模型部署服務的管理, 爲了增加 cpu 和 gpu 模型的統一部署功能, 爲了簡化運維操作,我們引入了 seldon 這個開源的基於雲原生的模型部署服務。
seldon 是一個基於 K8S 的集成的模型部署方案, 內置了很多通用的例如 tfserving、 sklearn server、mlflow server、triton 這樣的模型推理服務器 (inference server)。除了這些還可以通過自己實現自定義的 inference server 提供一些額外的模型服務支持。
seldon 通過將你的模型部署爲 K8S 上的微服務,來提供 HTTP/GRPC 接口給業務調用。
我們來看下 seldon 的核心模塊, 如下圖所示:
seldon 的核心模塊是它的 Seldon Core Controller, 即 operator 模塊, 該模塊用來管理 Seldon Deployment 資源 (Custom Resource)。seldon 通過 CRD 向 K8S 註冊自定義資源,Seldon Core Controller 負責處理該資源的 CRUD, 我們通過創建 / 刪除 / 修改 Seldon Deployment 來達到創建 / 刪除 / 修改模型服務的目的。
除此之外, seldon 還可以集成 Prometheus 和 Jaeger 來提供模型服務的指標監控和調用追蹤能力。
seldon 的另一核心概念是 Model Server , 即加載模型用來提供 HTTP 接口的模型推理服務器。Model Server 有兩種類型, 分爲 Reusable Model Servers 和 Non-Reusable Model Servers 。他們的差別從名字就可以看出, 前者是不同模型之間可複用的,後者是固定模型的。
Reusable Model Servers 通過配置的模型地址,從外部的模型倉庫下載模型, seldon 模型預置了較多的開源模型推理服務器, 包含 tfserving , triton 都屬於 Reusable Model Servers。
Non-Resuable Model Servers 將模型打入自定義鏡像內部,不需要單獨從外部加載模型, 適合做一些特殊化處理以及不需要頻繁更新的場景。
例如啓動一個 tensorflow 的模型服務, mnist.yaml 文件定義如下:
apiVersion: machinelearning.seldon.io/v1alpha2
kind: SeldonDeployment
metadata:
name: tfserving
spec:
name: mnist
predictors:
- graph:
children: []
implementation: TENSORFLOW_SERVER
modelUri: gs://seldon-models/tfserving/mnist-model
name: mnist-model
parameters:
- name: signature_name
type: STRING
value: predict_images
- name: model_name
type: STRING
value: mnist-model
name: default
replicas: 1
這裏聲明一個名爲 minist 的 SeldonDeployment 資源,主要的配置參數就是 implementation 和 modelUri。
implementation 指定此次 Model Server 使用預置的 tfserving 服務器, 並且需要指定模型的 modelUri 地址。
通過 kubectl create -f mnist.yaml 我們就可以創建一個 Seldon Deployment 資源。
通過 kubectl get sdep 可以看到的 Seldon Deployment minist,該 Seldon Deployment 資源會管理對應的所需要的 Deployment、 Service 和 Virtual Service。
3.2 設計方案
基於公司內部 K8S 環境,在商量了如何部署 seldon 的後,我們最後決定的架構如圖所示:
在引入 seldon 管理模型服務部署的同時,進行了以下的改造:
-
保留 ABox master 作爲 Dubbo 請求接入入口, master 負責將請求根據協議封裝成 http 請求 K8S 集羣的 ingress controller
-
修改 Ingress Controller 爲 Nginx Ingress Controller, 通過爲每個模型服務生成 Ingress 規則路由到指定的 K8S service
-
增加 HDFS-Intializer 用於 Reusable Model Server 中的 hdfs:// 協議的 modelUri
-
基於騰訊雲的 GpuManager 方案實現 GPU 的虛擬化和共享
-
通過在算法平臺集成 K8S client 進行 Seldon Deployment 和 Ingress 的 CRUD
-
爲自定義鏡像提供日誌收集服務
-
爲模型服務增加資源使用展示
下面來介紹 seldon 模型服務部署的主要改造部分。
3.2.1 Ingress Controller 替換
seldon 通過 Ingress Controller 來提供集羣外服務的統一訪問, 然後通過 istio 或者 ambassador 提供服務的路由和分流, 默認的 istio 服務較爲強大,但由於公司內部 K8S 不提供 istio 服務的維護,爲了便於運維, 我們在部署 seldon operator 的時候關閉了 istio 和 ambassador 的功能,然後通過自己的客戶端實現在 seldon deployment 和 ingress 的統一創建 / 刪除 / 更新管理。
3.2.2 Reusable Model Server 模型初始化
seldon 的默認模型下載協議只支持 s3://、 gs://, 我們的模型文件目前存儲於 HDFS 管理, 所以實現了自定義的 HDFS-INITILIZER 負責 HDFS 模型文件的拉取。
3.2.3 GPU 方案
我們都知道在 k8s 上使用 GPU 資源有 NVIDIA 的 k8s device plugin ,但是這種方案的缺點是不支持 GPU 的共享和隔離, 也就是一個 pod 的 container 必須佔用整數個 GPU。在我們的實際使用中, 有一些小模型需要 GPU 加速但是隻佔用小部分顯卡資源。
目前主流的方案有:
由於公司使用的騰訊雲並且 GpuManager 方案功能較強大,所以我們考察了騰訊雲的開源 GpuManager 方案和騰訊雲新升級的 vGpu 方案,在權衡後,選擇了 GpuManager。
理由是:
-
由於 vGpu 實現內核級別的 cuda 請求攔截,需要依賴騰訊自研的 TencentOS, 不利於服務器內部統一運維,另外 TencentOS 基於 Centos 8, 在公司目前普遍還是 Centos 7 的情況下, 無法安裝基礎監控服務,也不利於運維
-
vGPU 在積極研發推進階段,但是目前還不支持服務配置獨佔 N 張 GPU 卡的情況
雖然 GpuManager 滿足功能需求,但是也存在約 5% 的性能損耗。
3.2.4 日誌管理
對於自定義的鏡像的模型服務, 我們定製了 cpu 和 gpu 版本 (主要支持 pytorch)的基礎鏡像,通過在基礎鏡像內置 databus(filebeat) 實現日誌上傳到 kafka, 再通過自研 log-server 服務消費 kafka 寫入日誌文件,並且對日誌文件進行定期清理,備份到 HDFS。
log-server 提供了 HTTP 的訪問接口可以獲取到最新的日誌。
3.2.5 資源監控
通過定時收集每個 pod 的 cpu, memory 使用量, 我們粗略的統計了每個服務的最小 / 最大 / 平均資源使用情況, 並且在界面提供實時資源使用的展示。
3.2.6 服務遷移
在完成基本功能開發後, 我們依次對 QA、預發、生產環境進行了已有的模型服務的遷移, 這個過程比較長。爲了不影響生產的模型服務, 我們定製了流量切換開關, 逐步按比例切流線上服務到新的集羣, 保證業務調用無痛無感知。
3.3 注意點
tfserving 依賴 avx 指令集,在某些 KVM 虛機上無法啓動 tfserving 服務, Container 提示狀態爲 CrashLoopBackOff。
進入容器直接運行:
/usr/bin/tensorflow_model_server --port=9000 --model_name=xxx --model_base_path=/path/to/model
可以看到錯誤輸出:
Illegal instruction (core dumped)
tfserving 默認需要 avx 、avx2 的支持, 可以通過 lscpu 檢查機器支持的對應指令集。
四、 總結與展望
第一階段模型服務改造已經告一段落,我們具備了通用化的模型部署能力, 並且依託於 K8S 簡化了運維。但是目前模型服務部署仍有更多的優化點, 比如:
-
支持推理圖
我們目前的模型服務爲單模型的服務, seldon 支持更復雜的圖推理的結果, 可以在模型服務前後配置 INPUT TRANSFORMER 和 OUTPUT TRANSFORMER 進行輸入輸出的處理。 -
支持多種發佈策略、分流策略
支持灰度發佈可以更爲穩妥的支持線上模型在線推理服務的更新, 分流策略的支持可以用來衡量多版本模型之間的性能差異和效果比對。 -
支持自定義 Model Server 鏡像的自動打包更新
-
支持更多模型 intializer
如對象存儲的支持。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/0P4ujjJE9OaIabz7frJWAg