技術乾貨:解密最受歡迎的開源 Serverless 框架彈性技術實現

Knative 是一款基於 Kubernetes 的開源 Serverless 應用編排框架,其目標是制定雲原生、跨平臺的 Serverless 應用編排標準。Knative 主要功能包括基於請求的自動彈性、縮容到 0、多版本管理、基於流量的灰度發佈以及事件驅動等。

彈性是 Serverless 中的核心能力,那麼 Knative 作爲 CNCF 社區最受歡迎的開源 Serverless 應用框架,提供了哪些與衆不同的彈性能力呢?本文將帶你深入瞭解 Knative 的彈性實現。(說明:本文基於 Knative 1.8.0 版本進行分析)

Knative 提供了基於請求的自動彈性實現 KPA(Knative Pod Autoscaler),也支持 K8s 中的 HPA,此外 Knative 提供了靈活的彈性擴展機制,可以結合自身業務需要,擴展彈性實現。這裏我們也會介紹與 MSE 結合實現精準彈性以及與 AHPA 結合實現基於請求的彈性預測。

首先我們介紹 Knative 原生最具吸引力的彈性:KPA。

基於請求的自動彈性 KPA

基於 CPU 或者 Memory 的彈性,有時候並不能完全反映業務的真實使用情況,而基於併發數或者每秒處理請求數 (QPS/RPS),對於 web 服務來說更能直接反映服務性能,Knative 提供了基於請求的自動彈性能力。要獲得當前服務的請求數,Knative Serving 爲每個 Pod 注入 QUEUE 代理容器 (queue-proxy),該容器負責收集用戶容器併發數 (concurrency) 或請求數 (rps) 指標。Autoscaler 定時獲取這些指標之後,會根據相應的算法,調整 Deployment 的 Pod 數量,從而實現基於請求的自動擴縮容。

圖片來源:https://knative.dev/docs/serving/request-flow/

基於請求數的彈性算法

Autoscaler 基於每個 Pod 的平均請求數(或併發數)進行彈性計算。默認情況下 Knative 使用基於併發數的自動彈性, 默認 Pod 的最大併發數爲 100。此外 Knative 中還提供了一個叫 target-utilization-percentage 的概念,稱之爲目標使用率,取值範圍 0~1,默認是 :0.7。

以基於併發數彈性爲例,Pod 數計算方式如下:

POD數=併發請求總數/(Pod最大併發數*目標使用率)

例如服務中 Pod 最大併發數設置了 10,這時候如果接收到了 100 個併發請求,目標使用率設置爲 0.7,那麼 Autoscaler 就會創建了 15 個 POD(100/(0.7*10) 約等於 15)。

縮容到 0 的實現機制

使用 KPA 時當無流量請求時,會將 Pod 數自動縮容到 0;當有請求時,會從 0 開始擴容 Pod。那麼 Knative 中是如何實現這樣的操作呢?答案是通過模式切換。

Knative 中定義了 2 種請求訪問模式:Proxy 和 Serve。Proxy 顧名思義,代理模式,也就是請求會通過 activator 組件進行代理轉發。Serve 模式是請求直達模式,從網關直接請求到 Pod,不經過 activator 代理。如下圖:

模式的切換是由 autoscaler 組件負責,當請求爲 0 時,autoscaler 會將請求模式切換爲 Proxy 模式。這時候請求會通過網關請求到 activator 組件,activator 收到請求之後會將請求放在隊列中,同時推送指標通知 autoscaler 進行擴容,當 activator 檢測到由擴容 Ready 的 Pod 之後,隨即將請求進行轉發。而 autoscaler 也會判斷 Ready 的 Pod,將模式切換爲 Serve 模式。

應對突發流量

突發流量下如何快速彈資源

KPA 涉及到 2 個與彈性相關的概念:Stable(穩定模式)和 Panic(恐慌模式),基於這 2 種模式,可以讓我們認識到 KPA 如何基於請求做到精細化彈性。

首先穩定模式是基於穩定窗口期,默認是 60 秒。也就是計算在 60 秒時間段內,Pod 的平均併發數。

而恐慌模式是基於恐慌窗口期,恐慌窗口期是通過穩定窗口期與 panic-window-percentage 參數計算得到。panic-window-percentage取值是 0~1,默認是 0.1。恐慌窗口期計算方式:恐慌窗口期=穩定窗口期 *panic-window-percentage。默認情況下也就是 6 秒。計算在 6 秒時間段內,Pod 的平均併發數。

KPA 中會基於穩定模式和恐慌模式 Pod 的平均併發數分別計算所需要的 Pod 數。

那麼實際根據哪個值進行彈性生效呢?這裏會依據恐慌模式下計算的 Pod 數是否超過恐慌閾值 PanicThreshold 進行判斷。恐慌閾值是通過 panic-threshold-percentage/100 計算出來,panic-threshold-percentage 參數默認是 200,也就是恐慌閾值默認是 2。當恐慌模式下計算出來的 Pod 數大於或等於當前 Ready Pod 數的 2 倍,那麼就會使用恐慌模式 Pod 數進行彈性生效,否則使用穩定模式 Pod 數。

顯然,恐慌模式的設計是爲了應對突發流量場景。至於彈性敏感度,則可以通過上述的可配置參數進行調節。

突發流量下如何避免 Pod 被打爆

KPA 中可以設置突發請求容量(target-burst-capacity)應對 Pod 被超預期的流量打爆。也就是通過這個參數值的計算,來調節請求是否切換到 Proxy 模式,從而通過 activator 組件作爲請求緩衝區。如果當前 ready pod 數*最大併發數-突發請求容量-恐慌模式計算出來的併發數 <0,意味着突發流量超過了容量閾值,則切換到 activator 進行請求緩衝。當突發請求容量值爲 0 時,只有 Pod 縮容到 0 時,才切換到 activator。當大於 0 並且 container-concurrency-target-percentage 設置爲 100 時,請求總是會通過 activator。-1 表示無限的請求突發容量。請求也總是會通過 activator。

減少冷啓動的一些技巧

延遲縮容

對於啓動成本較高的 Pod, KPA 中可以通過設置 Pod 延遲縮容時間以及 Pod 縮容到 0 保留期,來減少 Pod 擴縮容頻率。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/scale-down-delay: ""60s"
        autoscaling.knative.dev/scale-to-zero-pod-retention-period: "1m5s"
    spec:
      containers:
        - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56

調低目標使用率,實現資源預熱

Knative 中提供了目標閾值使用率的配置。通過調小該值可以提前擴容超過實際需要使用量的 Pod 數,在請求達到目標併發數之前進行擴容,間接的可以做到資源預熱。例如,如果 containerConcurrency 設置爲 10,目標利用率值設置爲 70(百分比),則當所有現有 Pod 的平均併發請求數達到 7 時,Autoscaler 將創建一個新 Pod。因爲 Pod 從創建到 Ready 需要一定的時間,通過調低目標利用率值可以做到提前擴容 Pod,從而減少冷啓動導致的響應延遲等問題。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/target-utilization-percentage: "70"
    spec:
      containers:
        - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56

配置 KPA

通過上面的介紹,我們對 Knative Pod Autoscaler 工作機制有了進一步的瞭解,那麼接下來介紹如何配置 KPA。Knative 中配置 KPA 提供了兩種方式:全局模式和 Revision 模式。

全局模式

全局模式可以修改 K8s 中的 ConfigMap:config-autoscaler,查看 config-autoscaler 使用如下命令:

kubectl -n knative-serving get cm config-autoscaler
apiVersion: v1
kind: ConfigMap
metadata:
 name: config-autoscaler
 namespace: knative-serving
data:
 container-concurrency-target-default: "100"
 container-concurrency-target-percentage: "70"
 requests-per-second-target-default: "200"
 target-burst-capacity: "211"
 stable-window: "60s"
 panic-window-percentage: "10.0"
 panic-threshold-percentage: "200.0"
 max-scale-up-rate: "1000.0"
 max-scale-down-rate: "2.0"
 enable-scale-to-zero: "true"
 scale-to-zero-grace-period: "30s"
 scale-to-zero-pod-retention-period: "0s"
 pod-autoscaler-class: "kpa.autoscaling.knative.dev"
 activator-capacity: "100.0"
 initial-scale: "1"
 allow-zero-initial-scale: "false"
 min-scale: "0"
 max-scale: "0"
 scale-down-delay: "0s"

參數說明:

參數 說明
container-concurrency-target-default 默認Pod最大併發數,默認值100
container-concurrency-target-percentage 併發數目標使用率,70實際表示0.7
requests-per-second-target-default 默認每秒請求數(rps),默認值200
target-burst-capacity 突發請求容量
stable-window 穩定窗口,默認60s
panic-window-percentage 恐慌窗口比例,默認值爲10,則表示默認恐慌窗口期爲6秒(60*0.1=6)
panic-threshold-percentage 恐慌閾值比例,默認值200
max-scale-up-rate 最大擴縮容速率,表示一次擴容最大數,實際計算方式:math.Ceil(MaxScaleUpRate * readyPodsCount)
max-scale-down-rate 最大縮容速率,表示一次縮容最大數,實際計算方式:math.Floor(readyPodsCount / MaxScaleDownRate)。默認值2表示,每次縮容一半。
enable-scale-to-zero 是否開始縮容到0,默認開啓
scale-to-zero-grace-period 優雅縮容到0的時間,也就是延遲多久縮容到0,默認30s
scale-to-zero-pod-retention-period pod縮容到0保留期,該參數適用於Pod啓動成本較高的情況
pod-autoscaler-class 彈性插件類型,當前支持的彈性插件包括:kpa、hpa、ahpa以及mpa(ask場景下配合mse支持縮容到 0)
activator-capacity activator請求容量
initial-scale 創建revision時,初始化啓動的Pod數,默認1
allow-zero-initial-scale 是否允許創建revision時,初始化0個Pod, 默認false,表示不允許
min-scale revision級別最小保留的Pod數量。默認0表示最小值可以爲0
max-scale revision級別最大擴容的Pod數量。默認0表示無最大擴容上限
scale-down-delay 表示延遲縮容時間,默認0表示立即縮容

Revision 版本模式

在 Knative 中可以爲每一個 Revision 配置彈性指標,部分配置參數如下:

  • 指標類型
    • 每個 revision 指標註解:autoscaling.knative.dev/metric
    • 支持的指標:"concurrency","rps","cpu","memory"以及其它自定義指標
    • 默認指標:"concurrency"
  • 目標閾值
    • autoscaling.knative.dev/target
    • 默認值:"100"
  • pod 縮容到 0 保留期
    • autoscaling.knative.dev/scale-to-zero-pod-retention-period
  • 目標使用率
    • autoscaling.knative.dev/target-utilization-percentage

配置示例如下:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/metric: "concurrency"
        autoscaling.knative.dev/target: "50"
        autoscaling.knative.dev/scale-to-zero-pod-retention-period: "1m5s"
        autoscaling.knative.dev/target-utilization-percentage: "80"

對 HPA 的支持

對於 K8s HPA, Knative 也提供天然的配置支持,可以在 Knative 使用基於 CPU 或者 Memory 的自動彈性能力。

  • 基於 CPU 彈性配置
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/class: "hpa.autoscaling.knative.dev"
        autoscaling.knative.dev/metric: "cpu"
  • 基於 Memory 的彈性配置
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/class: "hpa.autoscaling.knative.dev"
        autoscaling.knative.dev/metric: "memory"

彈性能力增強

Knative 提供了靈活的插件機制(pod-autoscaler-class),可以支持不同的彈性策略。阿里雲容器服務 Knative 當前支持的彈性插件包括:kpa、hpa、精準彈性擴縮容 mpa 以及 具有預測能力的 ahpa。

保留資源池

在原生的 KPA 能力之上,我們提供了保留資源池的能力。該功能可以應用在如下場景:

  • ECS 與 ECI 混用。如果希望常態情況下使用 ECS 資源,突發流量使用 ECI, 那麼我們可以通過保留資源池來實現。如單個 Pod 處理的併發 10,保留資源池 Pod 數爲 5,那麼常態下通過 ECS 資源可以應對不超過 50 的併發請求。如果併發數超過 50,那麼 Knative 就會擴容新的 Pod 數來滿足需求,新擴容出來的資源使用 ECI。

  • 資源預熱。對於完全使用 ECI 的場景,也可以通過保留資源池實現資源預熱。當在業務波谷時使用保留實例替換默認的計算型實例,當第一個請求來臨時使用保留實例提供服務,同時也會觸發默認規格實例的擴容。當默認規格實例擴容完成以後所有新請求就會都轉發到默認規格上,同時保留實例則不會接受新的請求,並且等保留實例所有接收到的請求處理完成以後就會被下線。通過這種無縫替換的方式實現了成本和效率的平衡,即降低了常駐實例的成本又不會有顯著的冷啓動時長。

精準彈性擴縮容

單個 Pod 處理請求的吞吐率有限,如果多個請求轉發到同一個 Pod,會導致服務端過載異常,因此需要精準的控制單個 Pod 請求併發處理數。尤其對一些 AIGC 場景下,單個請求會佔用較多的 GPU 資源,需要嚴格的限制每個 Pod 併發處理的請求數。

Knative 與 MSE 雲原生網關結合,提供基於併發數精準控制彈性的實現:mpa 彈性插件。

mpa 會從 MSE 網關獲取併發數,並計算所需要的 Pod 數進行擴縮容,而 MSE 網關可以做到基於請求精準轉發。

配置示例如下:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/class: mpa.autoscaling.knative.dev
        autoscaling.knative.dev/max-scale: '20'
    spec:
      containerConcurrency: 5
      containers:
      - image: registry-vpc.cn-beijing.aliyuncs.com/knative-sample/helloworld-go:73fbdd56
        env:
        - name: TARGET
          value: "Knative"

參數說明:

參數 說明
autoscaling.knative.dev/class: mpa.autoscaling.knative.dev mpa表明使用MSE指標進行擴縮容,支持縮容到0
autoscaling.knative.dev/max-scale: '20' 擴容Pod數上限是20
containerConcurrency: 5 表示單個Pod能處理的最大併發數是5

彈性預測 AHPA

容器服務 AHPA(Advanced Horizontal Pod Autoscaler)可以根據業務歷史指標,自動識別彈性週期並對容量進行預測,解決彈性滯後的問題。

當前 Knative 支持 AHPA(Advanced Horizontal Pod Autoscaler)的彈性能力,當請求具有周期性時,可通過彈性預測,實現預熱資源。相比於調低閾值進行資源預熱,通過 AHPA 可以最大程度的提升資源利用率。

此外由於 AHPA 支持自定義指標配置,Knative 與 AHPA 結合可以做到基於消息隊列以及響應延遲 rt 的自動彈性。

基於 rps 使用 AHPA 配置示例如下:

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: autoscale-go
  namespace: default
spec:
  template:
    metadata:
      labels:
        app: autoscale-go
      annotations:
        autoscaling.knative.dev/class: ahpa.autoscaling.knative.dev
        autoscaling.knative.dev/target: "10"
        autoscaling.knative.dev/metric: "rps"
        autoscaling.knative.dev/minScale: "1"
        autoscaling.knative.dev/maxScale: "30"
        autoscaling.alibabacloud.com/scaleStrategy: "observer"
    spec:
      containers:
        - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/autoscale-go:0.1

參數說明:

參數 說明
autoscaling.knative.dev/class: ahpa.autoscaling.knative.dev 指定彈性插件AHPA。
autoscaling.knative.dev/metric: "rps" 設置AHPA指標。目前支持concurrency、rps以及響應時間rt。
autoscaling.knative.dev/target: "10" 設置AHPA指標的閾值,本示例rps閾值爲10,表示單個Pod每秒最大處理請求數10。
autoscaling.knative.dev/minScale: "1" 設置彈性策略實例數的最小值爲1。
autoscaling.knative.dev/maxScale: "30" 設置彈性策略實例數的最大值爲30。
http://autoscaling.alibabacloud.com/scaleStrategy: "observer" 設置彈性伸縮模式,默認值是observer。observer:表示只觀察,但不做真正的伸縮動作。您可以通過這種方式觀察AHPA的工作是否符合預期。由於預測需要歷史7天的數據,因此創建服務默認是observer模式。auto:表示由AHPA負責擴容和縮容,把AHPA指標和閾值輸入到AHPA,AHPA最終決定是否生效。
  • ta-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal">
    參數 說明
    autoscaling.knative.dev/class: ahpa.autoscaling.knative.dev 指定彈性插件AHPA。
    autoscaling.knative.dev/metric: "rps" 設置AHPA指標。目前支持concurrency、rps以及響應時間rt。
    autoscaling.knative.dev/target: "10" 設置AHPA指標的閾值,本示例rps閾值爲10,表示單個Pod每秒最大處理請求數10。
    autoscaling.knative.dev/minScale: "1" 設置彈性策略實例數的最小值爲1。
    autoscaling.knative.dev/maxScale: "30" 設置彈性策略實例數的最大值爲30。
    http://autoscaling.alibabacloud.com/scaleStrategy: "observer" 設置彈性伸縮模式,默認值是observer。observer:表示只觀察,但不做真正的伸縮動作。您可以通過這種方式觀察AHPA的工作是否符合預期。由於預測需要歷史7天的數據,因此創建服務默認是observer模式。auto:表示由AHPA負責擴容和縮容,把AHPA指標和閾值輸入到AHPA,AHPA最終決定是否生效。
  • e data-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal">

小結

本文從 Knative 典型彈性實現 KPA 出發進行介紹,包括如何實現基於請求的自動彈性、縮容到 0、應對突發流量以及我們在 Knative 彈性功能上的擴展增強,包括保留資源池,精準彈性以及彈性預測能力。

作者:元毅

點擊立即免費試用雲產品 開啓雲上實踐之旅!

原文鏈接

本文爲阿里雲原創內容,未經允許不得轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章