眾所周知,Kubernetes 有個親生的 HPA 組件,在云原生早期,這個名義上的自動擴縮容的能力給 Kubernetes 贏得了不少掌聲。當然現在回頭看看,僅僅根據 CPU 和內存這樣“貧瘠”的指標,不論是用于判斷負載水平,還是用于計算擴容目標,都不是很夠用的。這個階段里,HPA 的擴縮容效率也是廣受詬病的一個問題,在一個多級微服務調用的業務場景里,壓力是逐級傳遞的,下圖展示了一個常見情況:
圖片
如上圖,用戶流量進入集群之后:
這個逐級傳遞的過程不僅緩慢,而且可以說是步步驚心——每一級的擴容都是直接被 CPU 或內存的飆高觸發的,被“沖垮”的可能性是普遍存在的。這種被動、滯后的方式,很明顯是有問題的。
造成 HPA 窘境的原因之一,就是“自掃門前雪”,每個 Pod 都只能根據自身負載情況來進行擴縮容決策。如果能夠直接根據業務流量的變化進行決策,并且將流量流經的所有微服務進行擴縮容,看起來情況就會好很多了。HPA 的自定義指標支持,給這個問題了一個可行的方案。該能力讓 HPA 可以用其它的指標來作為擴縮容的觸發器,例如我們可以用 Promethues 采集消息中間件的深度或者負載均衡器的隊列長度,作為一個更能如實反映業務流量的指標,直接用來觸發相關的多個微服務的擴縮容,如下圖所示:
圖片
在上圖中:
這中間涉及到的 Prometheus Adapter,通過配置文件完成步驟 2 的轉換:
- seriesQuery: '{__name__=~"^container_.*_total",container!="POD",namespace!="",pod!=""}' resources: overrides: namespace: {resource: "namespace"} pod: {resource: "pod"} seriesFilters: # since this is a superset of the query above, we introduce an additional filter here - isNot: "^container_.*_seconds_total$" name: {matches: "^container_(.*)_total$"} metricsQuery: "sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[2m])) by (<<.GroupBy>>)"
當然,完全可以自行實現 Aggregated API 來支持這種指標的采集和呈現工作。Prometheus 所提供的大量 Exporter 是吸引我們寫這種古怪語法的最大動力。
那么如果是 KEDA 的話,這個問題又如何呢?KEDA 提供了幾十個被稱為 Scaler 的東西,其中除了 Promethues 之外,還包括 Kafka、Redis、PostgreSQL 等多種選擇。所以在很多場景中,無需 Promethues,也能使用 Scaler 完成對輸入指標的讀取和判斷。下面用 KEDA 為例,看看這種伸縮方法的具體實現。
假設一個容器化應用由多個工作負載組成:
我們希望達成的效果是 —— Ingress、Backend 1、Backend 2、Database,實例數量保持在 1:2:1.5:2 的關系,Keda 的大致流程如下圖所示:
圖片
首先使用 Helm 安裝 KEDA:
$ helm repo add kedacore https://kedacore.github.io/charts$ helm install keda kedacore/keda --namespace defaultNAME: kedaLAST DEPLOYED: Wed Nov 29 18:56:36 2023NAMESPACE: defaultSTATUS: deployedREVISION: 1...
隨便創建幾個工作負載,冒充微服務:
$ kubectl create deploy ingress --image=nginxdeployment.apps/ingress created$ kubectl create deploy backend1 --image=nginxdeployment.apps/backend1 created$ kubectl create deploy backend2 --image=nginxdeployment.apps/backend2 created$ kubectl create deploy database --image=nginxdeployment.apps/database created$ kubectl get pods | cut -d - -f 1 | grep -v keda | sort...backend1backend2databaseingress
運行成功后,我們可以看到,四個微服務,每個微服務都有一個實例。
按照剛才瞎掰的比例,編寫一個 ScaleObject:
apiVersion: keda.sh/v1alpha1kind: ScaledObjectmetadata: name: bk1spec: scaleTargetRef: name: backend1 triggers: - type: kubernetes-workload metadata: podSelector: 'app=ingress' value: '0.5'---apiVersion: keda.sh/v1alpha1kind: ScaledObjectmetadata: name: bk2spec: scaleTargetRef: name: backend2 triggers: - type: kubernetes-workload metadata: podSelector: 'app=ingress' value: '0.67' ---apiVersion: keda.sh/v1alpha1kind: ScaledObjectmetadata: name: dbspec: scaleTargetRef: name: database triggers: - type: kubernetes-workload metadata: podSelector: 'app=ingress' value: '0.5'
上述代碼引入了 kubernetes-workload 類型的觸發器,他會監控 app=ingress 的容器,并對 scaleTargetRef 中提到的工作負載數量比例進行擴縮容。
提交到集群之后,會看到實例數量數量發生了變化:
$ kubectl get pods | cut -d - -f 1 | sort | uniq --count... 2 backend1 2 backend2 2 database 1 ingress 3 keda
我們把 Ingress 擴容到 2 實例,再次統計:
$ kubectl scale deployment ingress --replicas=2deployment.apps/ingress scaled$ kubectl get pods | cut -d - -f 1 | sort | uniq --count... 4 backend1 3 backend2 4 database 2 ingress 3 keda
可以看到,的確是按照我們設定的比例,同步產生了縮放。如果縮減 Ingress 服務實例數,幾分鐘之后,其它工作負載也會隨之縮容。
$ kubectl scale deployment ingress --replicas=1deployment.apps/ingress scaled$ kubectl get pods | cut -d - -f 1 | sort | uniq --count /... 2 backend1 2 backend2 2 database 1 ingress
雖說云原生架構的復雜性問題越來越被強調,但是這一生態的宗旨應該還是沒有變化——用簡單的透明的手段解決復雜問題。
本文鏈接:http://www.www897cc.com/showinfo-26-35285-0.html一篇學會用 KEDA 根據工作負載進行快速擴容
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: Git 難用?有救!
下一篇: useEffect 實踐案例之一