爲什麼 Serverless 能提升資源利用率?

業務的負載往往不是一成不變的,而是隨着時間呈現一定的上下波動。傳統的應用構建方式一般是備足充分的資源以保障業務可用性,造成資源利用率不高的現象。隨着容器技術的普及,應用可以通過彈性伸縮或者應用混部的方式來提升資源利用率,但由於資源管理的複雜度,難以在業務可用性和資源利用率上取得較好的平衡。

Serverless 平臺的出現,將資源管理的責任從用戶側轉移到平臺側。這種責任轉移能夠讓用戶專注在業務開發上,而平臺本身利用其資源規模和負載多樣性的優勢,專注在資源利用率的提升上。業務使用 Serverless 平臺能夠大幅提升資源利用率,實現降本提效的效果。

利用率的問題

業務的負載是動態變化的,而資源的彈性往往跟不上負載變化,所以會出現資源利用率不高的情況。爲了簡化部署運維的複雜度,一般應用在部署時往往指定固定的實例數,此時資源和負載的變化如下圖所示:

可以看到,有大量的時間存在資源的浪費,按日平均資源利用率來計算不到 30%。而資源利用率直接關係到成本,如果資源利用率提升一倍,成本就能下降 50%。最理想的情況是資源完全貼合負載,如下圖所示:

但現實的情況是很難做到,原因有兩個:

  1. 負載的變化可以是很快的,但是資源的創建卻需要更長的時間
  2. 資源的彈性成功率不是 100%,出於穩定性考慮需要預留資源 Buffer

因此,實際的資源狀況是介於上述兩種情況之間,業務開發者可以通過一些手段來提升資源利用率,使其逼近 100%。接下來我們看一下一些常用的提升資源利用率的手段。

提升利用率:彈性伸縮

容器化的應用通常會使用彈性伸縮來提升資源利用率。最典型的是使用 K8s 的 HPA 策略[1],設置一個 CPU 利用率閾值,當容器的 CPU 利用率超過閾值時自動增加容器,低於閾值時自動減少容器。使用 HPA 後業務負載和資源變化情況如下:

可以看到,在新增的資源創建完成之前,已有的資源要留有一些餘量以緩衝負載的上升。在上面這種階梯形的資源變化情況下利用率是多少呢?讓我們來定量地分析一下。

可以看到,需要預留的資源和負載的上升幅度以及擴容時間有關。假設在擴容時間 T 內,負載從 A 上升到 B,實際需要的資源從 xA 擴容到 xB。爲了在資源創建完成之前能夠接住負載,當負載爲 A 時需要有的資源量是 xB,則資源利用率是負載增長斜率和擴容時間的一個函數。當負載的增長比例 K 確定時,資源利用率 Util 是一個關於擴容時間 T 的反向函數,擴容時間越短,則資源利用率越高。

例如在負載每分鐘增加 100% 的情況下,資源利用率和擴容時間的關係。

  • 當擴容時間爲 1 分鐘時,資源利用率爲 50%
  • 當擴容時間爲 5 分鐘時,資源利用率爲 17%

擴容時間是提升資源利用率的關鍵。從負載開始上升,到新容器創建完成,整個擴容時間可以分解成如下圖所示:

  1. 反應時間
    1. 指標採集時間:例如 CPU 指標的採集需要取一段時間內的 CPU 平均利用率
    2. 決策時間:例如 CPU 指標的採集需要連續 N 次大於閾值纔會觸發擴容
  2. 啓動時間
    1. 系統冷啓動:系統準備機器和容器環境的時間
    2. 應用冷啓動:容器啓動後應用的初始化時間,例如 JVM 的啓動,初始化中間件,加載數據等等

如何縮短擴容時間?下面對比 K8s 和函數計算 FC[2]在各個階段的優化:

時間 K8s 函數計算 FC
指標採集時間 15s 0併發度根據請求實時計算
決策時間 0K8s 默認的 Stabilization window [3]爲 0 0併發度根據請求實時計算
系統冷啓動 鏡像:~30s管控+調度+容器啓動 代碼包:200ms鏡像:3s容器池化、代碼包/鏡像加速
應用冷啓動 10ms ~ 10min 10ms ~ 10min

函數計算 FC 通過請求級別的調度,將反應時間縮短到 0;通過代碼包和鏡像加速,將冷啓動時間優化到最低 200ms。在應用冷啓動時間相同的情況下,函數計算 FC 的擴容時間比 K8s 快 1 分鐘。若應用冷啓動較快(10s),則函數計算 FC 的資源利用率會大幅優於 K8s;若應用冷啓動較慢(1min),則 K8s 的利用率和函數計算 FC 差距變小。如下圖所示:

應用冷啓動時間的優化,在函數計算 FC 場景下能夠大幅提升資源利用率。但是由於應用冷啓動和具體的應用邏輯相關,比較難做通用的優化。一些可能的優化方向有:

  1. 應用改造:將 Java 應用改造成 Nodejs/Python 等輕量的函數,將鏡像改造成代碼包方式,但改造代價較大。
  2. 函數快照:將已經初始化完成的函數實例做成鏡像,通過鏡像快速拉起新的實例。但鏡像打破了實例的獨特性,例如一些應用初始化生成的 UUID 在同一鏡像拉起的實例中會衝突。
  3. 數據加載加速:一些應用在初始化時需要從 OSS 加載大量數據,系統可以通過 Cache/P2P 等方式加速數據的加載

總結下 HPA 存在的一些問題:

  1. 彈性速度問題:彈性速度慢導致 buffer 留得多,利用率低
  2. 縮容速度問題:縮容速度慢,有觀察窗口
  3. CPU 閾值難以設置:靠業務經驗,往往過低

提升利用率:混部超賣

容器化的應用提升資源利用率的另一種方式是混部和超賣。容器集羣的使用模式有兩種:

  1. 經典 K8s 模式:有節點池,Pod 創建在節點上,需要關注容器利用率和節點資源分配率
  2. Serverless K8s 模式:無節點池,Pod 由 Serverless Container 承載,只需要關注容器資源利用率

在經典 K8s 模式下,容器的彈性伸縮並沒有提升資源利用率,即使將容器刪除掉了,節點也還在。而節點的彈性伸縮不如容器靈活。在這種情況下,混部和超賣是提升資源利用率的常見做法。

在 K8s 裏面通過 resource.request[4]< resource.limit 來實現超賣:K8s 在調度時根據 resource.request 來分配容器,但是根據 resource.limit 來限制容器的資源使用。

可以看到,一個節點上的容器的最大使用資源加起來,會超過節點的資源限制。能這樣做的假設是每個容器的資源使用不會同時達到 resource.limit,否則就會產生資源競爭,導致性能下降甚至 OOM。但這樣的假設並不總是成立的,每個容器的資源使用是動態變化的,這樣就有一定的概率會出現資源競爭。混部超賣要達到較好的效果並不容易,影響混部效果的因素包括資源池大小,負載多樣性,性能穩定性,超載遷移策略等。

首先是資源池大小,資源池越大,發生資源競爭的概率就越小。讓我們來定量分析一下競爭的概率:假設有 4 個應用,每個應用的資源使用量有 50% 概率是 1,50% 概率是 2。我們來對比將它們放在一個大的資源池和兩個小的資源池的發生競爭的概率:

可以看到大資源池的概率要明顯低於小資源池。最直觀的,A和C同時爲2的時候,在小資源池模式下必然產生競爭,但是在大資源池下未必會產生競爭。對於具體的業務應用來說,由於負載規模不大,資源池也就比較小,混部產生競爭的概率就會較大。

其次是負載的多樣性,負載越多樣越互補,混部的效果就越好,資源利用率就越高。這種多樣性既包括資源需求的多樣性,例如有的負載是 CPU 密集型而有的是 IO 型的;也包括時間波動的多樣性,例如有的負載是早高峯而有的是晚高峯。

對於具體的業務應用來說,負載的多樣性不夠,資源利用率難以進一步提高。

最後是超載遷移,當節點的負載過高時,需要將一部分容器遷移到其他的節點。這個遷移過程需要是平滑的,不影響業務。在 K8s 中調度器是不感知應用請求流量的,因此在超載遷移時,需要應用層通過健康檢查、優雅上下線等機制配合進行遷移。如果沒有及時遷移就會導致請求失敗影響服務質量。

總結下混部存在的一些問題:

  1. 資源池不夠大:資源競爭概率高
  2. 負載多樣性不夠:資源競爭概率高,利用率不高
  3. 超載遷移不平滑:節點超載時流量遷移不平滑

提升利用率:Serverless

彈性伸縮和混部超賣是提升資源利用率的有效方式,但由於其固有的複雜度屬性,業務開發者往往需要投入較大的精力才能取得較好的效果,而這些基礎設施相關的工作,往往不是業務開發者的核心競爭力。業務開發者之所以需要想盡方法來提升資源利用率,最根本的問題是機器是屬於業務開發者的。能否將業務開發者從機器運維中解放出來呢?Serverless 提供了一種產品形態,將資源管理的責任從用戶側轉移到平臺側。這樣,業務開發者只需要爲業務請求付費,而無需關注資源利用率,專注在業務創新上。

Serverless 並不是沒有服務器了,而是將服務器的管理、運維和利用率提升這些工作集中到平臺側,發揮平臺在資源規模、負載多樣性上的優勢,提升機器的資源利用率。下圖是 Serverless 系統的內部架構,通過系統側的流量管理、彈性伸縮和混部超賣,提升集羣的資源利用率:

  1. 通過深度垂直優化,提升冷啓動速度,做到彈得快
  2. 通過吸收不同的業務負載,擴大資源池規模,增加負載多樣性,提升混部效率

從用戶側來看,利用 Serverless 平臺提供的能力來提升業務側的資源利用率:

a. 請求調度[5]:按請求時間計費,閒置時間不計費,實例的時間利用率爲 100%

b. 閒置計費[6]:應對應用冷啓動慢的業務,提供預留實例閒置計費,當實例沒有請求時,費用降低到 1/10

c. 動態併發度:針對 CPU 閾值設置過低的問題,系統根據實際流量動態決定最佳併發度,尋找吞吐拐點

結論

由於負載的動態變化,資源的容量評估和利用率提升,是困擾業務開發者的問題。通過彈性伸縮和混部超賣來提升資源利用率的方式由於其固有的複雜度,實施的效果並不理想。Serverless 平臺將資源管理的責任從用戶側轉移到平臺側,讓業務開發者專注在業務開發上,而平臺本身利用其資源規模和負載多樣性的優勢,專注在資源利用率的提升上,實現共贏。

對於業務開發者而言,根據應用的特點,可以採取如下的選型路徑:

  1. 對於啓動快的應用,直接使用按量模式,達到 100% 利用率
  2. 對於啓動慢的應用,可以選擇優化啓動速度,也可以選擇使用預留模式+閒置計費,提升利用率
  3. 可以立即開始使用 Serverless 的應用:定時任務,Web-hook

相關鏈接:

[1] HPA 策略

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/

[2] 函數計算 FC

https://www.aliyun.com/product/fc

[3] Stabilization window

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#default-behavior

[4] resource.request

https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

[5] 請求調度

https://help.aliyun.com/document_detail/179379.htm?spm=a2c4g.54301.0.0.474b5feezaRWiK#p-kwb-hz6-6e3

[6] 閒置計費

https://help.aliyun.com/document_detail/185038.htm?spm=a2c4g.54301.0.0.1fc515f93M64Wd#section-sw6-nzj-rbs

作者:木吳 阿里雲智能高級技術專家

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

原文鏈接

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

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