談一談企業級彈性伸縮與優化建設

 

什麼是彈性伸縮?彈性伸縮和成本優化是何關係? 應該如何做好企業級彈性伸縮與成本優化建設?

一 背景

傳統意義上來講,彈性伸縮主要解決的問題是容量規劃與實際負載的矛盾, 這矛盾通常因爲資源使用普遍具有以下幾個問題導致:

(1)在線服務申請資源時考慮到突發流量和服務穩定性,預留大量的 buffer 資源,造成資源申請量普遍遠超實際使用量。

(2)大部分在線服務的潮汐現象、波峯波谷特徵非常明顯,保留過多常態資源造成巨大浪費。

(3)開發和運維評估和配置的資源規格不合理,並且動態更新不及時。

隨着雲原生技術的發展,容器雲的彈性能力進入大衆視野,彈性伸縮也成爲各大服務器廠商的標準配置,在高速發展的互聯網企業中,彈性既能支撐業務優雅面對突發的大流量、亦能在業務低峯時伸縮資源維持低成本運行,尤其在當前的大環境下, 降本增效的彈性能力建設是必然。那應該如何打造我們的彈性伸縮能力、又如何利用彈性的能力解決高昂的成本問題?本文根據筆者過去的實踐和思考, 簡單闡述對計算資源彈性、容器雲 kubernetes[1] 彈性、混合雲彈性、Serverless[2] 等的一些心得體會。

閱者受益:

  1. 計算資源彈性能力方向建設

  2. 容器雲集羣彈性方向建設

  3. 容器雲應用彈性方向建設

  4. 混合雲彈性建設

  5. Serverless 方向建設

二 計算資源彈性能力建設

業務還未部署在容器雲的時候, 資源是私有云或公有云的虛擬機爲主,設計彈性平臺的落地產出就是提升虛擬機的資源利用率, 降低服務器成本和動態感知業務增長, 實現平滑擴容

彈性平臺建設

彈性平臺基於應用資源畫像的洞察 - 分析 - 優化方向建設, 整體架構包括可視化端層、計算層(數據獲取、應用分析、彈性決策設定)、實施自動化,核心就是通過對資源使用率監控數據進行洞察分析,感知不同業務線的資源使用情況,對資源持續低負載或高負載有全局視角, 判斷應用是否需要進行伸縮活動, 因爲虛擬機資源的伸縮活動是分鐘級(5 分鐘)以上的, 做不到容器雲的秒級彈性, 所以還要考慮虛機資源池化

計算資源彈性平臺架構

 這裏主要對決策樹稍加闡述, 設定的算法邏輯主要考慮以下幾點:

當然資源成本優化也會考慮雲商折扣、資源的類型譬如包年包月、按量付費、Spot 搶佔實例的組合方式等,Spot 搶佔實例在容器雲中發揮的作用比較大,會在下文介紹

三 容器雲集羣層面優化

隨着雲原生的發展, Kubernetes 容器編排成爲業務上雲的首選。業界在容器上建設的路線基本遵循 Docker > Kubernetes > ServiceMesh > Serverless  。因爲容器雲是當下的主流, 所以下面會用比較大的篇幅來介紹容器雲的彈性伸縮及優化方式

容器雲彈性分爲集羣彈性和容器應用彈性兩個層面。容器應用層面的彈性屬於 K8S 的 HPA 或者 VPA 資源管理的範疇, 集羣層面的彈性屬於 k8S 的節點伸縮、動態調度等,本節從集羣彈性講起,主要包括以下內容:

3.0、集羣資源構成

相比虛機類的彈性, 容器雲環境的彈性是更爲智能、高效的、可落地的。以 CPU 資源爲例,一個 Kubernetes 集羣的 Node 節點資源組成結構大致如下:

Kubernetes Node 資源構成

 3.1、Kubernetes 彈性優化總覽

   Kubernetes 彈性優化總覽

3.2、集羣彈性 CA

Kubernetes AutoScaling 提供多種機制來滿足 Pod 自動伸縮需求:

我先聊一聊集羣 Node 級別的彈性伸縮, 依託官方的 ClusterAutoscaler 組件,它可以根據部署的應用所請求的資源量來動態的伸縮集羣,不同雲廠商也分別實現了各自的 Provider 接入,對應的容器集羣產品也都提供了彈性伸縮的功能,大家自行開啓即可。如果你用的是自建集羣, 可以參考雲商實現適配自己集羣的 Provider。

在集羣中部署 CA 主要解決以下幾個問題:

1 思考需要多大的集羣節點規模滿足應用需求?

2 當 Pod Pending ,沒有可調度節點?

3 當多臺節點利用率低, 不能被自動釋放?

整體架構

Autoscaler:核心模塊,負責整體擴縮容功能

Estimator:負責評估計算擴容

Simulator:負責模擬調度,計算縮容

Cloud Provider:抽象了 CloudProvider 及 NodeGroup 等相關接口,與雲 API 交互

CA 架構

什麼時候擴?

由於資源不足,pod 調度失敗,導致 pod 處於 pending 狀態時,CA 會評估擴容節點過程, 新拉起一臺機器加入到集羣中

擴容流程

什麼時候縮?

當 Node 的資源利用率較低時,且此 Node 上存在的 POD 都能被重新調度到其他節點, CA 組件就會執行評估縮容節點過程, 將這臺 Node 節點上的 POD 驅逐到其他節點上,則此臺 Node 就可以被釋放 。需要注意適配縮容過程時需要考慮對 POD 的優雅調度 , Cordon[10] 節點 + Drain[11] 方式

縮容流程

什麼樣的節點不會被 CA 刪除

3.3、Node 節點超賣

Node 資源超賣方案是針對 Node 級別的資源調整方案,通過 AdmissionWebhook[13] 修改 K8s Node 的 Allocatable 實現, 達到在使用率較低的情況下,將原本較小的資源擴展爲邏輯上較大的資源來處理。例如原有 CPU 爲 4 核,超賣 2 倍則是可將這個 CPU 視作 8 核

Node Annotation xxx/cpu-oversold: "false" 開啓 & 關閉 Node 超賣增加靈活性

Node Annotation xxx/cpu-oversold-ratio=1.5  調整 Node 可分配值到 1.5 倍

超賣功能主要解決以下幾個問題:

1 應用資源一般申請都超標、真實負載不高

2 測試環境節點超賣 2-3 倍節省成本

整體架構

Node 超賣架構

靜態超賣

靜態超賣就是不考慮節點的真實負載, 只通過註解配置資源超賣比例

動態超賣

動態超賣就是根據每個節點的真實負載數據,進行不同比例的資源超賣或取消超賣

自研組件基於節點歷史監控數據,動態的 / 週期性的去調整超賣比例。比如某個 Node 連續 5m/1d 持續低負載並且節點已分配資源水位線很高了,那麼可以把超賣比例適當調高,以此使 Node 能容納更多的業務 Pod。如果節點已經是高負載, 那就維持或調小超賣比

當然超賣的設計也有常見一些問題需要考慮,譬如需要不斷平衡 Node 節點的超賣與真實使用率、要支持指標採集靈活性支持 1m 或更長 1d 的不同選擇、考慮大規模集羣(5k 節點)頻繁的 webhook 更新對調度的性能影響等

3.4、集羣調度

在使用 Node 節點超賣時, 我們其實還有一個動態調度器配合一起工作, 調度器感知超賣相關配置和資源實際使用情況, 爲應用穩定性和高效調度提供保證,  所以介紹下在調度層面可做的優化

靜態調度

Kubernetes 的資源編排調度默認使用的是靜態調度 Schedule[14],就是通過調度中預選 + 優選方式將 Pod 與 Node 綁定。靜態調度的好處就是調度簡單高效、集羣資源管理方便,最大的缺點也很明顯,就是不管節點實際負載,極容易導致集羣負載不高

動態調度

目前主要有 3 種擴展調度器方法:

因主版本受限, 我們內部還是使用的 extender, 通過實現 Filter  webhook 接口,接收 scheduler 請求 Filter 基於服務畫像(服務、節點的 cpu、mem 均值、方差、歐氏距離聚類算法)來優化調度

基本解決以下幾個問題:

1 分配高負載低的情況、分配低但實際負載高的情況

2 節點 CPU 高負載 75% 以上不進行調度

3 機器打分制, 譬如 ess 機器分數最低

4 在線離線混部資源分配限制

開啓自定義調度前

開啓自定義調度後

3.5、Descheduler 重調度

上面講到 kube-scheduler 默認是靜態調度,屬於'一次性'調度, 因爲 Pod 一旦被綁定了節點是不會自動觸發重新調度的,那在後續 node 節點數量、標籤、污點、容忍等的變動可能會導致已經被調度過的 pod 不是最優調度,  官方 descheduler[18] 組件補足了這一點。Descheduler 可以根據一些規則和配置策略來幫助我們重新平衡集羣狀態,其核心原理是根據其策略配置找到可以被移除的 Pod 並驅逐它們,其本身並不會進行調度被驅逐的 Pod,而是依靠默認的調度器來實現,目前支持的策略有:

3.6、離在線業務混部

因爲離線和在線業務有明顯的潮汐性,進行合理的混部提升資源利用率、降低成本的有效方案 。

離線和在線業務混部是彈性的深水區, 因爲不僅涉及調度部署、資源隔離與壓制、容災治理、跨部門合作等,所以一般也就只有大廠才真實落地

我介紹下我們在踐行混部的路線,混部涉及到的比較複雜, 這裏只介紹個思路, 大家也可以借鑑開源方案, 譬如阿里 Koordinator[19] 混部系統,騰訊的 Caelus[20] 混部方案等

整體架構

混部三步走

階段 1 實現 Hadoop 離線集羣的資源共享

階段 2 整機騰挪方案

階段 3 離在線服務容器化混部

3.7、Spot 搶佔實例

前文我們都是在介紹集羣層面的技術優化,這一節介紹的是 Spot 資源。Spot 搶佔實例的資源成本大概只佔按量實例的 30% 左右

Amazon EC2 Spot 實例讓您可以利用 AWS 雲中未使用的 EC2 容量。與按需實例的價格相比,使用 Spot 實例最高可以享受 90% 的折扣。得益於 AWS 的運行規模,Spot 實例可以在運行超大規模工作負載時實現規模並節省成本。您還可以選擇休眠、停止或終止 Spot 實例,只需提前兩分鐘通知,我們就會收回 EC2 容量。

我們得到兩個重要的信息, 1 spot 實例最高可以享受 90% 的折扣 2 實例終止提前兩分鐘通知 (阿里雲是 5 分鐘) 。那如果能用好搶佔實例,就可以大幅降低我們的成本,所以我們嘗試將雲上業務的流量承載方式設置爲如下:

因爲 Spot 實例具有隨時會被回收終止的特點,所以 Spot 實例比較適合靈活性較高或具有容錯性的應用程序,所以在 K8s 的無狀態業務負載節點我們大量使用了 Spot 實例。如果你用的是雲商的容器集羣,那雲商會提供 Spot 節點得選項, 如果是自建集羣, 那建議通過階段一、二完成建設

**整體架構 **

Kubernetes+Spot 搶佔架構

階段 1

階段 2

如果我們的業務達到很大的規模,建議通過離線訓練、容器集羣、優雅回收三個方向完整建設

spot 用法可以參考 容器成本降低 50%,攜程在 AWS Spot 上的實踐 [22]趣頭條 [23]SpotIO[24]

四 容器雲應用彈性方向建設

前文提到 kunernetes autoscaling 包括 Pod 級別的自動伸縮和 Node 級別的自動伸縮, 接下來就聊聊 Pod 級別的自動伸縮,基本包括:

4.1、水平伸縮 HPA

HPA[29] 會基於 kubernetes 集羣內置資源指標或者自定義指標來計算 Pod 副本需求數並自動伸縮 ,因爲伸縮的是副本數, 所以比較適合無狀態應用 deployment。kubernetes HPA 原生支持依據 CPU/Memory 資源利用率彈性伸縮,僅僅通過簡單的命令就可以創建出 hpa 伸縮對象

kubectl autoscale deployment hpa-demo --cpu-percent=10 --min=2 --max=5

整體架構

HPA 架構

Prometheus-adapter

在 HPA 實踐落地過程中,僅僅依賴 CPU/Memory 利用率彈性伸縮無法滿足業務在多指標擴縮、彈性伸縮穩定性方面的諸多需求,可以配置自定義的監控指標來,譬如 Prometheus-adapter[33]

  1. 如果 metrics 數據 pod 可以暴露,則 hpa 的 metrics type 可以爲 pod 類型,可以創建 servicemonitor[34] 從 pod 採集監控上報 prometheus,也可以 pod 直接上報給 prometheus

  2. 如果 metrics 數據來源爲 k8s 集羣外部,比如 ecs 上的各種 exporter,可以用 servicemonitor 從外部採集數據上報給集羣內的 prometheus,hpa 的 metrics type 爲 object 類型

HPA 接入 Prometheus-adapter

4.2、KEDA

我們看到原生 HPA 在支持多方數據指標時,需要做大量的工作來適配,並且原生 HPA 不支持預定的伸縮(解決彈性滯後的問題)、縮容到 0(解決測試環境資源浪費問題)等問題,所以就出現各種基於 HPA 的擴展, 譬如當前最廣泛應用的擴展器 KEDA[30]

KEDA 是用於 Kubernetes 的基於事件驅動彈性伸縮器,用戶只需要創建 ScaledObject 或 ScaledJob 來定義你想要伸縮的對象和你想要使用的觸發器,KEDA 會處理剩下的一切!

附上 KEDA 架構圖和對比原生 HPA 接入 Prometheus adapter 的對比圖

KEDA 架構

 HPA 接入外部指標架構

KEDA 接入外部指標架構

4.3、CronHPA、EHPA

CronHPA 工作的核心是基於檢測到的週期做 “定時規劃”,通過規劃實現提前擴容的目的

EHPA[31]、AHPA[32] 基於預測算法,提前觸發應用擴容,大家感興趣的可以深入研究下騰訊開源的基於 FinOps 爲核心理念的 Crane[31] 項目

EHPA 架構

4.4、垂直擴容 VPA

Vertical Pod Autoscaler[9] 是垂直擴容,根據 Pod 的資源利用率、歷史數據、異常事件,來動態調整負載的 Request 值的組件,主要關注在有狀態服務、單體應用的資源伸縮場景

整體架構

該項目包括 3 個組成部分:

VPA 架構

不過 VPA 也有一些限制條件:

除了 VPA, 還有沒有其他方式可以對資源設置的 request 資源進行彈性優化呢, 這裏也介紹另外兩種方式

4.5、CronVPA

基本的核心還是基於檢測到的週期做 “定時規劃”,根據業務的過去的監控數據,規劃實現提前修改 request 的目的, 雖然也避免不了 POD 要進行重建

4.6、POD Request 超賣

前文我們介紹過 Node 節點超賣,那還有一種更細粒度的就是 Pod 的資源超賣,實現方式一樣是通過 webhook 機制動態更改 Pod 的 request 設置(limit 不超賣),或者更簡單粗暴一些我們在研發申請資源的時候按照靜態超賣的配置比例調整 request 設定, 當然這裏要評估對業務穩定性的影響

五 基於混合雲彈性建設

從彈性的視角來講私有云平臺可以應對常態化業務訪問壓力,那如果遇到流量劇增,公有云更能提供成熟可靠的秒級彈性伸縮服,因此進行混合雲建設可以有效填補業務高低峯訪問對資源需求波動較大的業務需求場景,與私有云平臺實現優勢互補;當然混合雲的建設不僅是爲彈性,更多是爲議價、多活、容災考慮。如下我以私有云 IDC 和阿里云爲例,舉例其中一種混合雲的形態,數據層是 DTS[35] 同步、流量通過雲解析 DNS 實現按照權重分發:

混合雲架構

六 Serverless

文中提到的這些資源伸縮及優化的方式,無疑都需要有個強大的技術團隊來做支撐,並且這些對未來的大多數公司來講也不是彈性優化的首選,或許 Serverless 纔是雲原生彈性演進的未來

Serverless 不是特指某種技術,而是無服務器、按需彈性、按量計費、簡化運維等的工具結合, 通過一個應用引擎框架集成雲開發、FaaS、BaaS、託管 K8s、DevOps、服務治理、彈性等幫助業務輕鬆上雲

比較流行的的開源框架像 Serverless[36] Knative[37] OpenFass[38]

Serverless 架構

七 總結

本文介紹了企業能夠實施和採納的彈性伸縮及優化的建設路線,基於上述部分方向建設,我們成功將資源 CPU 平均利用率從 10% 提升到 30%,雲服務器月度成本降低 60%。本文更多是以全局視角讓大家理解在彈性伸縮及優化建設的方向,希望對大家有所幫助。並未介紹過多技術細節,後面有機會再對文中方案做細節介紹

參考資料

[1]:   https://kubernetes.io/  kubernetes

[2]:   https://en.wikipedia.org/wiki/Serverless_computing  "Serverless Wiki"

[3]:   https://kubernetes.io/docs/concepts/architecture/nodes/ "Node"

[4]:   https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/ "自定義調度"

[5]:   https://github.com/kubernetes-sigs/descheduler "重調度"

[6]:   https://aws.amazon.com/ec2/spot/?nc1=h_ls "Aws Spot"

[7]:   https://github.com/kubernetes/autoscaler "autoscaler"

[8]:   https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ "HPA"

[9]:   https://github.com/kubernetes/design-proposals-archive/blob/main/autoscaling/vertical-pod-autoscaler.md "VPA"

[10]:   https://kubernetes.io/zh-cn/docs/concepts/architecture/nodes/ "Cordon"

[11]:   https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/ "Drain"

[12]:   https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ "PDB"

[13]:   https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/ "Dynamic Admission Control"

[14]:   https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/ "Scheduler"

[15]:   https://kubernetes.io/docs/concepts/extend-kubernetes/#scheduler-extensions "擴展調度"

[16]:   https://kubernetes.io/docs/tasks/extend-kubernetes/configure-multiple-schedulers/ "多調度器"

[17]:   https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/ "scheduling-framework"

[18]:   https://github.com/kubernetes-sigs/descheduler "重調度"

[19]:   https://github.com/koordinator-sh/koordinator "koordinator"

[20]:   https://github.com/Tencent/Caelus "Caelus"

[21]:   https://hadoop.apache.org/ "hadoop"

[22]:   https://mp.weixin.qq.com/s/xqsNeN28TCS5YzesBUIsxw "乾貨 | 容器成本降低 50%,攜程在 AWS Spot 上的實踐"

[23]:   http://cloud.qutoutiao.net/ "趣頭條"

[24]:   https://spot.io/ "spotio"

[25]:   https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-fleet.html "spot-fleet"

[26]:   https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html "ASG"

[27]:   https://aws.amazon.com/cloudwatch/ "cloudwatch"

[28]:   https://aws.amazon.com/lambda/ "lambda"

[29]:   https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ "HPA"

[30]:   https://keda.sh/ "KEDA"

[31]:   https://github.com/gocrane/crane "EHPA"

[32]:   https://www.alibabacloud.com/blog/599120 "AHPA"

[33]:   https://github.com/kubernetes-sigs/prometheus-adapter "prometheus-adapter"

[34]:   https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md "prometheus-monitor" 

[35]:   https://help.aliyun.com/product/26590.html "阿里雲 DTS"

[36]:   https://www.serverless.com/ "serverless"

[37]:   https://knative.dev/ "knative"

[38]:   https://www.openfaas.com/ "openfaas" 

[39]:   https://cloud.tencent.com/developer/article/1505214 "騰訊自研業務上雲:優化 Kubernetes 集羣負載的技術方案探討"

[40]:   https://mp.weixin.qq.com/s/KCHlbyNyJyOuZ9WJyx1qxg Vivo 計算平臺彈性實踐

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/iOHr3QzML6kDV4__v29qPg