大型Kubernetes叢集的資源編排最佳化

千鋒Python唐小強發表於2020-08-24

雲原生這個詞想必大家應該不陌生了,容器是雲原生的重要基石,而Kubernetes經過這幾年的快速迭代發展已經成為容器編排的事實標準了。越來越多的公司不論是大公司還是中小公司已經在他們的生產環境中開始使用Kubernetes, 原生Kubernetes雖然已經提供了一套非常完整的資源排程及管理方案但是在實際使用過程中還是會碰到很多問題:

  1. 叢集節點負載不均衡的問題
  2. 業務建立Pod資源申請不合理的問題
  3. 業務如何更快速的擴容問題
  4. 多租戶資源搶佔問題

這些問題可能是大家在使用Kubernetes的過程中應該會經常遇到的幾個比較典型的資源問題,接下來我們將分別介紹在騰訊內部是如果解決和最佳化這些問題的。

叢集節點負載不均衡的問題

我們知道Kubernetes原生的排程器多是基於Pod Request的資源來進行排程的,沒有根據Node當前和過去一段時間的真實負載情況進行相關排程的決策。這樣就會導致一個問題在叢集內有些節點的剩餘可排程資源比較多但是真實負載卻比較高,而另一些節點的剩餘可排程資源比較少但是真實負載卻比較低, 但是這時候Kube-scheduler會優先將Pod排程到剩餘資源比較多的節點上(根據LeastRequestedPriority策略)。

大型Kubernetes叢集的資源編排最佳化

如上圖,很顯然排程到Node1是一個更優的選擇。為了將Node的真實負載情況加到排程策略裡,避免將Pod排程到高負載的Node上,同時保障叢集中各Node的真實負載儘量均衡,我們擴充套件了Kube-scheduler實現了一個基於Node真實負載進行預選和優選的動態排程器(Dynamic-scheduler)。

大型Kubernetes叢集的資源編排最佳化

Dynamic-scheduler在排程的時候需要各Node上的負載資料,為了不阻塞動態排程器的排程這些負載資料,需要有模組定期去收集和記錄。如下圖所示node-annotator會定期收集各節點過去5分鐘,1小時,24小時等相關負載資料並記錄到Node的annotation裡,這樣Dynamic-scheduler在排程的時候只需要檢視Node的annotation便能很快獲取該節點的歷史負載資料。

大型Kubernetes叢集的資源編排最佳化

為了避免Pod排程到高負載的Node上,需要先透過預選把一些高負載的Node過濾掉,如下圖所示(其中的過濾策略和比例是可以動態配置的,可以根據叢集的實際情況進行調整)Node2過去5分鐘的負載,Node3過去1小時的負載多超過了對應的域值所以不會參與接下來的優選階段。

大型Kubernetes叢集的資源編排最佳化

同時為了使叢集各節點的負載儘量均衡,Dynamic-scheduler會根據Node負載資料進行打分, 負載越低打分越高。如下圖所示Node1的打分最高將會被優先排程(這些打分策略和權重也是可以動態配置的)。

大型Kubernetes叢集的資源編排最佳化

Dynamic-scheduler只能保證在排程的那個時刻會將Pod排程到低負載的Node上,但是隨著業務的高峰期不同Pod在排程之後這個Node可能會出現高負載。為了避免由於Node的高負載對業務產生影響我們在Dynamic-scheduler之外還實現了一個Descheduler,它會監控Node的高負載情況將一些配置了高負載遷移的Pod遷移到負載比較低的Node上。

大型Kubernetes叢集的資源編排最佳化

業務如何更快速的擴容問題

業務上雲的一個重要優勢就是在雲上能實現更好的彈性伸縮,Kubernetes原生也提供了這種橫向擴容的彈性伸縮能力(HPA)。但是官方的這個HPA Controller在實現的時候用的是一個Gorountine來處理整個叢集的所有HPA的計算和同步問題,在叢集配置的HPA比較多的時候可能會導致業務擴容不及時的問題,其次官方HPA Controller不支援為每個HPA進行單獨的個性化配置。

大型Kubernetes叢集的資源編排最佳化

為了最佳化HPA Controller的效能和個性化配置問題,我們把HPA Controller單獨抽離出來單獨部署。同時為每一個HPA單獨配置一個Gorountine,並且每一個HPA多可以根據業務的需要進行單獨的配置。

大型Kubernetes叢集的資源編排最佳化

其實僅僅最佳化HPA Controller還是不能滿足一些業務在業務高峰時候的一些需求,比如在業務做活動的時候希望在流量高峰期之前就能夠把業務擴容好。這個時候我們就需要一個定時HPA的功能,為此我們定義了一個CronHPA的CRD和CronHPA Operator。CronHPA會在業務定義的時間進行擴容和縮容,同時還能和HPA一起配合工作。

大型Kubernetes叢集的資源編排最佳化

業務建立Pod資源申請不合理的問題

透過Dynamic-scheduler和Descheduler來保障叢集各節點的負載均衡問題。但是我可能會面臨另一個比較頭疼的問題就是叢集的整體負載比較低但是可排程資源已經沒有了,從而導致Pod Pending。這個往往是由於Pod 資源申請不合理或者業務高峰時段不同所導致的,那我們是否可以根據Node負載情況對Node資源進行一定比例的超賣呢。於是我們透過Kubernetes的MutatingWebhook來截獲並修改Node的可排程資源量的方式來對Node資源進行超賣。

大型Kubernetes叢集的資源編排最佳化

這裡需要注意的是節點的超賣控制需要比較靈活不能一概而論,比如負載高的Node超賣比例應該要設定比較小或者不能設定超賣。

多租戶資源搶佔問題

當平臺使用者增多的時候,如果對資源不做任何控制那麼各租戶之間資源搶佔是不可避免的。Kubernetes原生提供的ResourceQuota可以提供Namespace級別對資源配額限制。但是騰訊內部資源預算管理通常是按產品維度,而一個產品可能會包括很多Namespace的顯然ResourceQuota不太適合這種場景。其次ResourceQuota只有資源限制功能不能做資源預留,當業務要做活動的時候不能保證活動期間有足夠的資源可以使用。

大型Kubernetes叢集的資源編排最佳化

為了實現一個產品維度且有資源預留功能的配額管理功能,我們設計了一個DynamicQuota的CRD來管理產品在各叢集的配額。如下圖所示產品2在各叢集所佔的配額資源其它產品多無法使用。

大型Kubernetes叢集的資源編排最佳化

如果一個產品佔用配額一直不使用就可能會導致平臺資源的浪費,因此我們在產品配額預留的基礎上提供了在不同產品間配額借調的功能。如下圖所示產品1暫時不用的配額可以借調給產品2臨時使用。

大型Kubernetes叢集的資源編排最佳化

當平臺有多叢集的時候,產品配額需要如何分配。為了簡化配下發操作,如下圖所示管理員在下發產品配額的時候只需配置一個該產品的配額總量,配額下發模組會根據產品目前在各叢集的使用情況按比例分配到各個叢集。

大型Kubernetes叢集的資源編排最佳化

產品在各叢集的資源使用情況是會時刻變化的,所以產品在各叢集配額也需要根據業務的使用情況進行動態的調整。如下圖所示產品在叢集2中的配額已經快用完的時候,配額調整模組會動態的把配額從使用不多的叢集1和叢集3調到叢集2。

大型Kubernetes叢集的資源編排最佳化

線上業務和離線業務混合部署是雲平臺的發展趨勢,所以我們在設計配額管理的時候也把在離線配額控制考慮進去了。如下圖所示我們在叢集維度加了一個離線配額控制,一個叢集的離線業務資源使用不能超過該叢集總資源的30%(這個比例可以根據實際情況進行調整)。其次一個產品的線上業務和離線業務配額之和又不能超過產品在該叢集的總配額。

大型Kubernetes叢集的資源編排最佳化

總結

上面提到的方案只是簡單說了一下我們的一些解決問題的思路,其實在真正運作的過程中還有很多細節需要考慮和最佳化。比如:上面提到的產品配額管理如果一個產品的配額不足了,這時候業務有高峰需要進行HPA擴容,這時候配額管理模組需要對這種擴容最佳化並放行。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69923331/viewspace-2714042/,如需轉載,請註明出處,否則將追究法律責任。

相關文章