背景
云原生這個詞想必大家應該不陌生了,容器是云原生的重要基石,而Kubernetes經過這幾年的快速迭代發展已經成為容器編排的事實標準了,越來越多的公司不論是大公司還是中小公司已經在他們的生產環境中開始使用Kubernetes, 原生Kubernetes雖然已經提供了一套非常完整的資源調度及管理方案但是在實際使用程序中還是會碰到很多問題:
- 集群節點負載不均衡的問題
- 業務創建Pod資源申請不合理的問題
- 業務如何更快速的擴容問題
- 多租戶資源搶占問題
這些問題可能是大家在使用Kubernetes的程序中應該會經常遇到的幾個比較典型的資源問題,接下來我們將分別介紹在騰訊內部是如果解決和優化這些問題的,
集群節點負載不均衡的問題
我們知道Kubernetes原生的調度器多是基于Pod Request的資源來進行調度的,沒有根據Node當前和過去一段時間的真實負載情況進行相關調度的決策,這樣就會導致一個問題在集群內有些節點的剩余可調度資源比較多但是真實負載卻比較高,而另一些節點的剩余可調度資源比較少但是真實負載卻比較低, 但是這時候Kube-scheduler會優先將Pod調度到剩余資源比較多的節點上(根據LeastRequestedPriority策略),

如上圖,很顯然調度到Node1是一個更優的選擇,為了將Node的真實負載情況加到調度策略里,避免將Pod調度到高負載的Node上,同時保障集群中各Node的真實負載盡量均衡,我們擴展了Kube-scheduler實作了一個基于Node真實負載進行預選和優選的動態調度器(Dynamic-scheduler),

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

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

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

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

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

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

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

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

這里需要注意的是節點的超賣控制需要比較靈活不能一概而論,比如負載高的Node超賣比例應該要設定比較小或者不能設定超賣,
多租戶資源搶占問題
當平臺用戶增多的時候,如果對資源不做任何控制那么各租戶之間資源搶占是不可避免的,Kubernetes原生提供的ResourceQuota可以提供Namespace級別對資源配額限制,但是騰訊內部資源預算管理通常是按產品維度,而一個產品可能會包括很多Namespace的顯然ResourceQuota不太適合這種場景,其次ResourceQuota只有資源限制功能不能做資源預留,當業務要做活動的時候不能保證活動期間有足夠的資源可以使用,

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

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

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

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

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

總結
上面提到的方案只是簡單說了一下我們的一些解決問題的思路,其實在真正運作的程序中還有很多細節需要考慮和優化,比如:上面提到的產品配額管理如果一個產品的配額不足了,這時候業務有高峰需要進行HPA擴容,這時候配額管理模塊需要對這種擴容優化并放行,
【騰訊云原生】云說新品、云研新術、云游新活、云賞資訊,掃碼關注同名公眾號,及時獲取更多干貨!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/685.html
標籤:其他
下一篇:大資料平臺是否更應該容器化?
