久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

怎么進行Kubernetes集群調度器原理剖析及思考

172次閱讀
沒有評論

共計 8371 個字符,預計需要花費 21 分鐘才能閱讀完成。

這篇文章將為大家詳細講解有關怎么進行 Kubernetes 集群調度器原理剖析及思考,文章內容質量較高,因此丸趣 TV 小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

云環境或者計算倉庫級別(將整個數據中心當做單個計算池)的集群管理系統通常會定義出工作負載的規范,并使用調度器將工作負載放置到集群恰當的位置。好的調度器可以讓集群的工作處理更高效,同時提高資源利用率,節省能源開銷。

通用調度器,如 Kubernetes 原生調度器 Scheduler 實現了根據特定的調度算法和策略將 pod 調度到指定的計算節點(Node)上。但實際上設計大規模共享集群的調度器并不是一件容易的事情。調度器不僅要了解集群資源的使用和分布情況,還要兼顧任務分配速度和執行效率。過度設計的調度器屏蔽了太多的技術實現,以至于無法按照預期完成調度任務,或導致異常情況的發生,不恰當的調度器的選擇同樣會降低工作效率,或導致調度任務無法完成。

本文主要從設計原理、代碼實現兩個層面介紹 Kubernetes 的調度器以及社區對其的補充加強,同時對業界常用調度器的設計實現進行比較分析。通過本文,讀者可了解調度器的來龍去脈,從而為選擇甚至設計實現適合實際場景的調度器打下基礎。

注明:本文中代碼基于 v1.11 版本 Kubernetes 進行分析,如有不當之處,歡迎指正!

調度器的基本知識

1.1 調度器的定義

通用調度的定義是指基于某種方法將某項任務分配到特定資源以完成相關工作,其中任務可以是虛擬計算元素,如線程、進程或數據流,特定資源一般是指處理器、網絡、磁盤等,調度器則是完成這些調度行為的具體實現。使用調度器的目的是實現用戶共享系統資源的同時,降低等待時間,提高吞吐率以及資源利用率。

本文中我們討論的調度器是指大規模集群下調度任務的實現,比較典型的有 Mesos/Yarn(Apache)、Borg/Omega(Google)、Quincy(Microsoft) 等。構建大規模集群(如數據中心規模)的成本非常之高,因此精心設計調度器就顯得尤為重要。

常見類型的調度器的對比分析如下表 1 所示:

怎么進行 Kubernetes 集群調度器原理剖析及思考

1.2 調度器的考量標準

我們首先思考一下調度器是根據哪些信息來進行調度工作的,以及哪些指標可以用來衡量調度工作質量。

調度器的主要工作是將資源需求與資源提供方做全局最優的匹配。所以一方面調度器的設計需要了解不同類型的資源拓撲,另一方面還需要對工作負載有充分的認識。

了解不同類型的資源拓撲,充分掌握環境拓撲信息能夠使調度工作更充分的利用資源(如經常訪問數據的任務如果距數據近可以顯著減少執行時間),并且可以基于資源拓撲信息定義更加復雜的策略。但全局資源信息的維護消耗會限制集群的整體規模和調度執行時間,這也讓調度器難以擴展,從而限制集群規模。

另一方面,由于不同類型的工作負載會有不同的甚至截然相反的特性,調度器還需要對工作負載有充分的認識,例如服務類任務,資源需求少,運行時間長,對調度時間并不敏感;而批處理類任務,資源需求大,運行時間短,任務可能相關,對調度時間要求較高。同時,調度器也要滿足使用方的特殊要求。如任務盡量集中或者分散,保證多個任務同時進行等。

總的來說,好的調度器需要平衡好單次調度(調度時間,質量),同時要考慮到環境變化對調度結果的影響,保持結果最優(必要時重新調度),保證集群規模,同時還要能夠支持用戶無感知的升級和擴展。調度的結果需要滿足但不限于下列條件,并最大可能滿足盡可能優先級較高的條件:

資源使用率最大化

滿足用戶指定的調度需求

滿足自定義優先級要求

調度效率高,能夠根據資源情況快速做出決策

能夠根據負載的變化調整調度策略

充分考慮各種層級的公平性

1.3 鎖對調度器設計的影響

對于資源的調度,一定會涉及到鎖的應用,不同類型鎖的選擇將直接決定調度器的使用場景。類似 Mesos 等兩層調度器,一般采用悲觀鎖的設計實現方式,當資源全部滿足任務需要時啟動任務,否則將增量繼續申請更多的資源直到調度條件滿足;而共享狀態的調度器,會考慮使用樂觀鎖的實現方式,Kubernetes 默認調度器是基于樂觀鎖進行設計的。

我們首先通過一個簡單的例子,比較下悲觀鎖和樂觀鎖處理邏輯的不同,假設有如下的一個場景:

作業 A 讀取對象 O

作業 B 讀取對象 O

作業 A 在內存中更新對象 O

作業 B 在內存中更新對象 O

作業 A 寫入對象 O 實現持久化

作業 B 寫入對象 O 實現持久化

悲觀鎖的設計是對對象 O 實現獨占鎖,直到作業 A 完成對對象 O 的更新并寫入持久化數據之前,阻斷其他讀取請求。樂觀鎖的設計是對對象 O 實現共享鎖,假設所有的工作都能夠正常完成,直到有沖突產生,記錄沖突的發生并拒絕沖突的請求。

樂觀鎖一般會結合資源版本實現,同樣是上述中的例子,當前對象 O 的版本為 v1,作業 A 首先完成對對象 O 的寫入持久化操作,并標記對象 O 的版本為 v2,作業 B 在更新時發現對象版本已經變化,則會取消更改。

Kubernetes 調度器剖析

Kubernetes 中的計算任務大多通過 pod 來承載運行。pod 是用戶定義的一個或多個共享存儲、網絡和命名空間資源的容器的組合,是調度器可調度的最小單元。Kubernetes 的調度器是控制平面的一部分,它主要監聽 APIServer 提供的 pod 任務列表,獲取待調度 pod,根據預選和優選策略,為這些 pod 分配運行的節點。概括來說,調度器主要依據資源消耗的描述得到一個調度結果。

2.1 Kubernetes 調度器的設計

Kubernetes 的調度設計參考了 Omega 的實現,主要采用兩層調度架構,基于全局狀態進行調度,通過樂觀鎖控制資源歸屬,同時支持多調度器的設計。

兩層架構幫助調度器屏蔽了很多底層實現細節,將策略和限制分別實現,同時過濾可用資源,讓調度器能夠更靈活適應資源變化,滿足用戶個性化的調度需求。相比單體架構而言,不僅更容易添加自定義規則、支持集群動態伸縮,同時對大規模集群有更好的支持(支持多調度器)。

相比于使用悲觀鎖和部分環境視圖的架構(如 Mesos),基于全局狀態和樂觀鎖實現的好處是調度器可以看到集群所有可以支配的資源,然后搶占低優先級任務的資源,以達到策略要求的狀態。它的資源分配更符合策略要求,避免了作業囤積資源導致集群死鎖的問題。當然這會有搶占任務的開銷以及沖突導致的重試,但總體來看資源的使用率更高了。

Kubernetes 中默認只有一個調度器,而 Omega 的設計本身支持資源分配管理器共享資源環境信息給多個調度器。所以從設計上來說,Kubernetes 可以支持多個調度器。

2.2 Kubernetes 調度器的實現

Kubernetes 調度器的工作流程如下圖所示。調度器的工作本質是通過監聽 pod 的創建、更新、刪除等事件,循環遍歷地完成每個 pod 的調度流程。如調度過程順利,則基于預選和優選策略,完成 pod 和主機節點的綁定,最終通知 kubelet 完成 pod 啟動的過程。如遇到錯誤的調度過程,通過優先級搶占的方式,獲取優先調度的能力,進而重新進入調度循環的過程,等待成功調度。

2.2.1 調度循環的完整邏輯

Kubernetes 調度器完成調度的整體流程如下圖 1 所示。下面就每個步驟的實現邏輯進行說明。

怎么進行 Kubernetes 集群調度器原理剖析及思考(1)基于事件驅動啟動循環過程

Kubernetes 調度器維護 sharedIndexInformer,來完成 informer 對象的初始化工作。也就是調度器會監聽 pod 創建、更新、刪除的操作事件,主動更新事件緩存,并持久化到內存隊列,發起調度循環。

該過程的函數入口在

https://github.com/kubernetes/kubernetes/blob/9cbccd38598e5e2750d39e183aef21a749275087/pkg/scheduler/factory/factory.go#L631

怎么進行 Kubernetes 集群調度器原理剖析及思考(2)將沒有調度的 pod 加到調度器緩存并更新調度器隊列

Informer 對象負責監聽 pod 的事件,主要的事件類型有:針對已調度 pod 的 addPodToCache、updatePodInCache、deletePodFromCache 和針對未被調度 pod 的 addPodToSchedulingQueue、updatePodInSchedulingQueue、deletePodFromSchedulingQueue 六種事件。該過程的函數入口在:

https://github.com/kubernetes/kubernetes/blob/9cbccd38598e5e2750d39e183aef21a749275087/pkg/scheduler/eventhandlers.go

各類事件的含義如下表 2 所示:

怎么進行 Kubernetes 集群調度器原理剖析及思考

(3)對調度器隊列中的每個 pod 執行調度

這里需要指出的是,在單個 pod 調度的過程中,對于主機節點的調度算法是順序執行的。也就是說,pod 在調度的過程中會嚴格的順序執行 Kubernetes 內置的策略和優先級,然后選擇最合適的節點。

單個 pod 的調度過程分為預選和優選兩個階段。預選階段調度器根據一組規則過濾掉不符合要求的主機,選擇出合適的節點;優選階段通過節點優先級打分的方式(依據整體優化策略等),選擇出分值最高的節點進行調度。

單個 pod 的調度過程由以下函數作為入口:
https://github.com/kubernetes/kubernetes/blob/9cbccd38598e5e2750d39e183aef21a749275087/pkg/scheduler/scheduler.go#L457
怎么進行 Kubernetes 集群調度器原理剖析及思考

當然,調度的過程可能由于沒有滿足 pod 運行條件的節點而調度失敗,此時當 pod 有優先級指定的時候,將觸發競爭機制。具有高優先級的 pod 將嘗試搶占低優先級的 pod 資源。相關部分代碼實現如下:

怎么進行 Kubernetes 集群調度器原理剖析及思考 如果資源搶占成功,將在下一次調度循環時標記可調度過程。如果搶占失敗,調度程序退出。調度結果不保存意味著 pod 仍然會出現在未分配列表中。

(4)接下來檢查用戶提供的插件的條件是否滿足

Reserve 插件是 Kubernets 留給用戶進行擴展的接口,基于 reserver 插件用戶在這個階段可以設定自定義條件,從而滿足期望的調度過程。插件的入口函數在:
https://github.com/kubernetes/kubernetes/blob/9cbccd38598e5e2750d39e183aef21a749275087/pkg/scheduler/plugins/registrar.go

可以在 https://github.com/kubernetes/kubernetes/tree/9cbccd38598e5e2750d39e183aef21a749275087/pkg/scheduler/plugins/examples 查看插件擴展 reserver 接口進行自定義調度的示例。

(5)找到滿足的節點后,更新 Pod 對象的標簽,保存被調度節點的結果

該過程的函數入口在 https://github.com/kubernetes/kubernetes/blob/9cbccd38598e5e2750d39e183aef21a749275087/pkg/scheduler/scheduler.go#L517。
怎么進行 Kubernetes 集群調度器原理剖析及思考

(6)完成 pod 到節點的綁定

pod 到節點的綁定需要首先完成存儲卷的掛載,最后通過 pod 對象的更新,完成最后的綁定。具體代碼的邏輯可以參考:
https://github.com/kubernetes/kubernetes/blob/9cbccd38598e5e2750d39e183aef21a749275087/pkg/scheduler/scheduler.go#L524
。

(7)調度完成后,主協程返回,執行下一個調度

至此調度的完整流程就完成了,下面重點介紹下,在單個 pod 調度過程中 Kubernetes 主要是如何對節點進行選擇的,主要包括預選和優選兩種策略。

2.2.2 單個 pod 的調度流程

單個 pod 的調度過程如下圖 2 所示。主要包括由 pre-filter、filter、post-filter 的預選過程和 scoring 的優選過程。

怎么進行 Kubernetes 集群調度器原理剖析及思考 圖 2:單個 Pod 的調度過程

(1)pod 進入調度階段,首先進入預選環節

通過規則過濾找到滿足 pod 調度條件的節點。
怎么進行 Kubernetes 集群調度器原理剖析及思考

k8s 內置了許多過濾規則,調度器會按照事先定義好的順序進行過濾。內置的過濾規則主要包括檢查節點是否有足夠資源(例如 CPU、內存與 GPU 等)滿足 pod 的運行需求,檢查 pod 容器所需的 HostPort 是否已被節點上其它容器或服務占用,檢查節點標簽(label)是否匹配 pod 的 nodeSelector 屬性要求,根據 taints 和 toleration 的關系判斷 pod 是否可以調度到節點上 pod 是否滿足節點容忍的一些條件,還有檢查是否滿足 csi 最大可掛載卷限制等。
怎么進行 Kubernetes 集群調度器原理剖析及思考

(2) 經過預選策略對節點過濾后,進入優選階段

調度器根據預置的默認規則進行打分(優先級函數得分 * 權重的和),然后選擇分數最高的節點實現 pod 到節點的綁定。

怎么進行 Kubernetes 集群調度器原理剖析及思考Kubernetes 內置的優先級函數如下,主要包括平均分布優先級(SelectorSpreadPriority)、最少訪問優先級(LeastRequestedPriority)、平衡資源分布優先級(BalancedResourceAllocation)等。

怎么進行 Kubernetes 集群調度器原理剖析及思考SelectorSpreadPriority:為了更好的高可用,對同屬于一個 service、replication controller 或者 replica 的多個 Pod 副本,盡量調度到多個不同的節點上。

InterPodAffinityPriority:通過迭代 weightedPodAffinityTerm 的元素計算和,如果對該節點滿足相應的 PodAffinityTerm,則將“weight”加到和中,具有最高和的節點是最優選的。

LeastRequestedPriority:由節點空閑資源與節點總容量的比值,即由(總容量 - 節點上 Pod 的容量總和 - 新 Pod 的容量)/ 總容量)來決定節點的優先級。CPU 和 memory 具有相同權重,比值越大的節點得分越高。

BalancedResourceAllocation:CPU 和內存使用率越接近的節點優先級越高,該策略不能單獨使用,必須和 LeastRequestedPriority 同時使用,也就是說盡量選擇在部署 Pod 后各項資源更均衡的機器。

NodePreferAvoidPodsPriority(權重 1w):如果節點的 Anotation 沒有設置 key-value:scheduler. alpha.kubernetes.io/ preferAvoidPods =“…”,則該 節點對該 policy 的得分就是 10 分,加上權重 10000,那么該節點對該 policy 的得分至少 10W 分。如果節點的 Anotation 設置了 scheduler.alpha.kubernetes.io/preferAvoidPods =“…”,如果該 pod 對應的 Controller 是 ReplicationController 或 ReplicaSet,則該節點對該 policy 的得分就是 0 分。

NodeAffinityPriority:實現 Kubernetes 調度中的親和性機制。

TaintTolerationPriority : 使用 Pod 中 tolerationList 與 節點 Taint 進行匹配,配對成功的項越多,則得分越低。

Kubernetes 調度器的不足和解決思路

3.1 典型的幾個問題和解決思路

(1)調度器只根據當前資源環境情況進行一次調度,一旦完成調度就沒有機制實現調整

雖然 pod 只有在自己退出、用戶刪除以及集群資源不足等情況下才會有變化。但資源拓撲的變化是隨時都有可能發生的,如批處理任務會結束,節點會新增或崩潰。這些情況導致調度的結果可能在調度時是最優的,但在拓撲變化后調度質量由于以上情況的發生而下降。

經過社區討論,認為需要重新找出不滿足調度策略的 pod,刪除并創建替代者來重新調度,據此設計啟動了項目 descheduler。

(2)調度以單個 pod 進行的,因而調度互相關聯的工作負載會難以實現

如大數據分析、機器學習等計算多依賴于批處理任務,這類工作負載相關性大,互相之間有依賴關系。為了解決這個問題,社區經過討論,提出了 coscheduling 一次調度一組 pod 的項目,以此來優化這類調度任務的執行。

(3)目前調度器的實現只關心是否能將 pod 與節點綁定,資源使用情況的數據未被充分利用

目前,集群的使用量只能通過監控數據間接推導。如果 k8s 集群剩余資源不足時,并沒有直觀數據可以用來觸發擴容或者告警。

根據上述情況,社區啟動了 cluster-capacity framework 項目,提供集群的容量數據,方便集群的維護程序或者管理員基于這些數據做集群擴容等。也有項目抓取監控數據自己計算集群的整體負載情況給調度算法參考,如 poseidon。

3.2 Kubernetes 調度器的定制擴展

如上節所述,通用調度器在某些場景下并不能滿足用戶個性化需求,實際環境下運行的集群的調度器,往往需要根據實際的需求做定制與二次開發。

kubernetes 的調度器以插件化的形式實現的,方便用戶對調度的定制與二次開發。定制調度器有如下幾種方式的選擇:

更改 Kubernetes 內置策略,通過更改默認的策略文件或者重新編譯調度器來實現。

擴展調度器在 pre-filter、filter、post-filter、reserve、prebind、bind 和 post-bind 各個階段的接口,更改調度器過濾、打分、搶占、預留的具體實現邏輯。

更改調度器調度算法,從頭實現調度器邏輯。
怎么進行 Kubernetes 集群調度器原理剖析及思考

企業場景應用的案例

4.1 通用計算場景

Kubernetes default-scheduler 滿足通用計算的需求,主要服務于以快速開發測試為目標的持續集成和持續部署平臺(DevOps 平臺)、以標準三層架構應用為特點的容器應用運行與運維平臺(容器平臺)、PaaS 平臺和云原生應用的核心基礎架構平臺(aPaaS 平臺)幾種場景。

通常情況下,標準 Kubernetes 調度器能夠滿足大多數通過計算場景的訴求,主要解決應用上云過程中不同異構云資源之間的調度問題,應用上云后彈性伸縮、故障自愈等的動態調度響應,標準中間件服務和數據庫服務基于日常運維規范的調度問題以及云原生應用在服務治理、配置管理、狀態反饋、事件鏈路跟蹤上的綜合調度過程。

4.2 批處理場景

大數據分析和機器學習類任務執行時需要大量資源,多個任務同時進行時,資源很快會用盡,部分任務會需要等待資源釋放。這類型任務的步驟往往互相關聯,單獨運行步驟可能會影響最終結果。使用默認的調度器在集群資源緊張時,甚至會出現占用資源的 pod 都在等待依賴的 pod 運行完畢,而集群沒有空閑資源去運行依賴任務,導致死鎖。所以在調度這類任務時,支持群組調度(在調度作業所需的資源都收集完成后才進行調度),減少了 pod 數量,因而降低調度器的負載,同時避免了很多資源緊張帶來的問題。

與默認調度器一次調度一個 pod 不同,kube-batch 定義了 PodGroup 定義一組相關的 pod 資源,并實現了一個全新的調度器。調度器的流程基本與默認調度器相同。Podgroup 保證一組 pod 可以同時被調度。是 Kubernetes 社區在大數據分析場景中的一種實現。

4.3 特定領域業務場景

特定的業務場景需要調度器能夠快速生成調度的策略,并盡可能避免調度超時。Poseidon 是大規模集群中基于圖應用數據局部性減少任務執行時間同時混合多種調度算法提升調度速度的一種調度器。

Poseidon 是基于 Firmament 算法的調度器,它通過接收 heapster 數據來構建資源使用信息。調用 Firmament 實現進行調度。Firmament 算法受 Quincy[11] 啟發,構建一個從任務到節點的圖,但作者為減少調度時間,將兩種計算最短路徑的算法合并,將全量環境信息同步改為增量同步。讓 Firmament 處理短時間批量任務時快于 Quincy,在資源短缺時沒有 Kubernetes 默認調度器超時的問題。

主要從設計原理、代碼實現等層面介紹 Kubernetes 的調度器以及社區對其的補充加強,總結了 Kubernetes 調度器的設計原理以及在何種場景如何增強 Kubernetes 來滿足業務需求,提供技術選型的依據和評價標準。

關于怎么進行 Kubernetes 集群調度器原理剖析及思考就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計8371字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 唐河县| 巩留县| 巫山县| 绥棱县| 兰州市| 高碑店市| 葫芦岛市| 龙南县| 宜都市| 新沂市| 西乌珠穆沁旗| 沂水县| 岱山县| 台南县| 大悟县| 鞍山市| 镇康县| 沂水县| 曲麻莱县| 简阳市| 安国市| 琼海市| 安达市| 兴山县| 凤翔县| 乐清市| 大邑县| 娱乐| 锦州市| 北票市| 五大连池市| 略阳县| 东丰县| 莱阳市| 枣阳市| 黄浦区| 乃东县| 洛宁县| 昌乐县| 积石山| 新津县|