Volcano火山:容器與批量計算的碰撞_台中搬家公司

4{icon} {views}

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

【摘要】 Volcano是基於Kubernetes構建的一個通用批量計算系統,它彌補了Kubernetes在“高性能應用”方面的不足,支持TensorFlow、Spark、MindSpore等多個領域框架,幫助用戶通過Kubernetes構建統一的容器平台。

Kubernetes 是當前非常流行的容器編排框架,在其發展早期重點以微服務類應用為主。隨着Kuberentes的用戶越來越多,更多的用戶希望在Kubernetes上運行BigData和AI框架,如Spark、TensorFlow等以構建統一的容器平台。但在Kubernetes運行這些高性能應用時,Kubernetes的默認調度器無法滿足高性能應用的需求,例如:公平調度、優先級、隊列等高級調度功能。由於Kubernetes的默認調度器是基於Pod進行調度,雖然在1.17中引入了調度框架,但仍無法滿足高性能應用對作業級調度的需求。

容器批量計算平台Volcano

針對雲原生場景下的高性能應用場景,華為雲容器團隊推出了Volcano項目。Volcano是基於Kubernetes構建的一個通用批量計算系統,它彌補了Kubernetes在“高性能應用”方面的不足,支持TensorFlow、Spark、MindSpore等多個領域框架,幫助用戶通過Kubernetes構建統一的容器平台。Volcano作為容器調度系統,不僅包括了作業調度,還包含了作業生命周期管理、多集群調度、命令行、數據管理、作業視圖及硬件加速等功能。

而在調度方面,Volcano 又對場景進行了細分、歸類,並提供了相關的方案及算法;同時也為這些功能提供了調度框架,方便用戶對調度器進行擴展。對於分佈式計算或是并行計算來說,根據場景和作業屬性的不同,也可以對其進行細分;在 《并行計算導論》 中將并行計算大致分為三類:

  • 簡單的并行

簡單的并行指多個子任務(tasks)之間沒有通信也不需要同步,可以完全的并行的執行。比較著名的例子應該就屬MapReduce了,它的兩個階段都屬於這種類型:mapper任務在執行時並不會彼此通信同步運行狀態;另一個常見的例子是蒙特·卡羅方法 ,各個子任務在計算隨機數時也無需彼此通信、同步。由於這種并行計算有比較廣泛的應用,例如 數據處理、VatR 等,針對不同的場景也產生了不同的調度框架,例如 Hadoop、DataSynapse 和 Symphony。同時,由於子任務之間無需信息和同步,當其中某幾個計算節點(workers)被驅逐后,雖然作業的執行時間可能會變長,但整個作業仍可以順利完成;而當計算節點增加時,作業的執行時間一般都會縮短。因此,這種作業也常常被稱作 Elastic Job。

  • 複雜的并行

複雜的并行作業指多個子任務 (tasks) 之間需要同步信息來執行複雜的并行算法,單個子任務無法完成部分計算。最近比較有名的例子應該算是 Tensorflow 的 “ps-work模式” 和 ring all-reduce 了,各個子任務之間需要大量的數據交換和信息同步,單獨的子任務無法獨立完成。正是由於作業的這種屬性,對作業調度平台也提出了相應的調度要求,比如 gang-scheduling、作業拓撲等。由於子任務之間需要彼此通信,因此作業在啟動后無法動態擴展子任務,在沒有checkpoint的情況下,任一子任務失敗或驅逐,整個作業都需要重啟,這種作業也常常被稱作 Batch Job,傳統的HPC場景多屬於這種類型的并行作業,針對這種場景的調度平台為 Slurm/PBS/SGE/HTCondor 等。

  • 流水線并行

流水線并行是指作業的多個子任務之間存在依賴關係,但不需要前置任務完全結束后再開始後續的任務;比如 Hadoop 里有相應的研究:在 Map 沒有完全結束的時候就部分開始 Reduce 階段,從而提高任務的并行度,提高整體的運行性能。符合這種場景的應用相對來說比較少,一般都做為性能優化;因此沒有針對這種場景的作業管理平台。需要區分一下工作流與流水線并行,工作流一般指作業之間的依賴關係,而流水線并行一般指作業內部多個任務之間的依賴。由於工作流中的作業差異比較大,很難提前開始後續步驟。

值得一提的是”二次調度”。由於簡單并行的作業一般會有大量的子任務,而且每個子任務所需要的資源相對一致,子任務之間也沒有通信和同步;使得資源的復用率相對比較高,因此二次調度在這種場景下能發揮比較大的作用;Hadoop的YARN,Symphony的EGO都屬於這種類型。但是在面對複雜并行的作業時,二次調度就顯得有也吃力;複雜并行作業一般並沒有太多的子任務,子任務之間還經常需要同時啟動,子任務之間的通信拓撲也可能不同 (e.g. ps/worker, mpi),而且作業與作業之間對資源的需求差異較大,因此導致了資源的復用率較低。

雖然針對兩種不同并行作業類型有不同的作業、資源管理平台,但是根本的目標都是為作業尋找最優的資源;因此,Volcano一直以支持以多種類型的作業為目標進行設計。目前,Volcano可以同時支持 Spark、TensorFlow和MPI等多種類型的作業。

常見調度場景

1.組調度 (Gang-scheduling)

運行批處理作業(如Tensorflow/MPI)時,必須協調作業的所有任務才能一起啟動;否則,將不會啟動任何任務。如果有足夠的資源并行運行作業的所有任務,則該作業將正確執行; 但是,在大多數情況下,尤其是在prem環境中,情況並非如此。在最壞的情況下,由於死鎖,所有作業都掛起。其中每個作業只成功啟動了部分任務,並等待其餘任務啟動。

2.作業級的公平調度 (Job-based Fair-share)

當運行多個彈性作業(如流媒體)時,需要公平地為每個作業分配資源,以滿足多個作業競爭附加資源時的SLA/QoS要求。在最壞的情況下,單個作業可能會啟動大量的pod資源利用率低, 從而阻止其他作業由於資源不足而運行。為了避免分配過小(例如,為每個作業啟動一個Pod),彈性作業可以利用協同調度來定義應該啟動的Pod的最小可用數量。 超過指定的最小可用量的任何pod都將公平地與其他作業共享集群資源。

3.隊列 (Queue)

隊列還廣泛用於共享彈性工作負載和批處理工作負載的資源。隊列的主要目的是:

  • 在不同的“租戶”或資源池之間共享資源
  • 為不同的“租戶”或資源池支持不同的調度策略或算法

這些功能可以通過層次隊列進一步擴展,在層次隊列中,項目被賦予額外的優先級,這將允許它們比隊列中的其他項目“跳轉”。在kube批處理中,隊列被實現為集群範圍的CRD。 這允許將在不同命名空間中創建的作業放置在共享隊列中。隊列資源根據其隊列配置(kube batch#590)按比例劃分。當前不支持分層隊列,但正在進行開發。

集群應該能夠在不減慢任何操作的情況下處理隊列中的大量作業。其他的HPC系統可以處理成百上千個作業的隊列,並隨着時間的推移緩慢地處理它們。如何與庫伯內特斯達成這樣的行為是一個懸而未決的問題。支持跨越多個集群的隊列可能也很有用,在這種情況下,這是一個關於數據應該放在哪裡以及etcd是否適合存儲隊列中的所有作業或pod的問題。

4.面向用戶的, 跨隊列的公平調度 (Namespace-based fair-share Cross Queue)

在隊列中,每個作業在調度循環期間有幾乎相等的調度機會,這意味着擁有更多作業的用戶有更大的機會安排他們的作業,這對其他用戶不公平。 例如,有一個隊列包含少量資源,有10個pod屬於UserA,1000個pod屬於UserB。在這種情況下,UserA的pod被綁定到節點的概率較小。

為了平衡同一隊列中用戶之間的資源使用,需要更細粒度的策略。考慮到Kubernetes中的多用戶模型,使用名稱空間來區分不同的用戶, 每個命名空間都將配置一個權重,作為控制其資源使用優先級的手段。

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

5.基於時間的公平調度 (Fairness over time)

對於批處理工作負載,通常不要求在某個時間點公平地分配資源,而是要求在長期內公平地分配資源。例如,如果有用戶提交大作業,則允許用戶(或特定隊列)在一定時間內使用整個集群的一半, 這是可以接受的,但在下一輪調度(可能是作業完成后數小時)中,應懲罰此用戶(或隊列)而不是其他用戶(或隊列)。在 HTCondor 中可以看到如何實現這種行為的好例子。

6.面向作業的優先級調度 (Job-based priority)

Pod優先級/搶佔在1.14版本中被中斷,它有助於確保高優先級的pod在低優先級的pod之前綁定。不過,在job/podgroup級別的優先級上仍有一些工作要做,例如高優先級job/podgroup應該嘗試以較低優先級搶佔整個job/podgroup,而不是從不同job/podgroup搶佔幾個pod。

7.搶佔 (Preemption & Reclaim)

通過公平分享來支持借貸模型,一些作業/隊列在空閑時會過度使用資源。但是,如果有任何進一步的資源請求,資源“所有者”將“收回”。 資源可以在隊列或作業之間共享:回收用於隊列之間的資源平衡,搶佔用於作業之間的資源平衡。

8.預留與回填 (Reservation & Backfill)

當一個請求大量資源的“巨大”作業提交給kubernetes時,當有許多小作業在管道中時,該作業可能會餓死,並最終根據當前的調度策略/算法被殺死。為了避免飢餓, 應該有條件地為作業保留資源,例如超時。當資源被保留時,它們可能會處於空閑和未使用狀態。為了提高資源利用率,調度程序將有條件地將“較小”作業回填到那些保留資源中。 保留和回填都是根據插件的反饋觸發的:volcano調度器提供了幾個回調接口,供開發人員或用戶決定哪些作業應該被填充或保留。

Volcano 調度框架

Volcano調度器通過作業級的調度和多種插件機制來支持多種作業;Volcano的插件機制有效的支撐了針對不同場景算法的落地,從早期的gang-scheduling/co-scheduling,到後來各個級別的公平調度。下圖展示了Volcano調度器的總體架構:

Cache 緩存了集群中Node和Pod信息,並根據PodGroup的信息重新構建 Job (PodGroup) 和 Task (Pod) 的關係。由於在分佈式系統中很難保證信息的同步,因此調度器經常以某一時間點的集群快照進行調度;並保證每個調度周期的決定是一致的。在每個調度周期中,Volcano 通過以下幾個步驟派發作業:

  • 在每個調度周期都會創建一個Session對象,用來存儲當前調度周期的所需的數據,例如,Cache 的一個快照。當前的調度器中僅創建了一個Session,並由一個調度線程執行;後續將會根據需要創建多個Session,併為每個Session分配一個線程進行調度;並由Cache來解決調度衝突。
  • 在每個調度周期中,會按順序執行 OpenSession, 配置的多個動作(action)和CloseSession。在 OpenSession中用戶可以註冊自定義的插件,例如gang、 drf,這些插件為action提供了相應算法;多個action根據配置順序執行,調用註冊的插件進行調度;最後,CloseSession負責清理中間數據。

(1) action是第一級插件,定義了調度周期內需要的各個動作;默認提供 enqueue、allocate、 preempt和backfill四個action。以allocate為例,它定義了調度中資源分配過程:根據 plugin 的 JobOrderFn 對作業進行排序,根據NodeOrderFn對節點進行排序,檢測節點上的資源是否滿足,滿足作業的分配要求(JobReady)后提交分配決定。由於action也是基於插件機制,因此用戶可以重新定義自己的分配動作,例如 基於圖的調度算法firmament。

(2) plugin是第二級插件,定義了action需要的各個算法;以drf插件為例,為了根據dominant resource進行作業排序,drf插件實現了 JobOrderFn函數。JobOrderFn函數根據 drf 計算每個作業的share值,share值較低代表當前作業分配的資源較少,因此會為其優先分配資源;drf插件還實現了EventHandler回調函數,當作業被分配或搶佔資源后,調度器會通知drf插件來更新share值。

  • Cache 不僅提供了集群的快照,同時還提供了調度器與kube-apiserver的交互接口,調度器與kube-apiserver之間的通信也都通過Cache來完成,例如 Bind。
  • 同時,為了支持上面這些場景,Volcano的調度器還增加了多個Pod狀態以提高調度的性能:
  • Pending: 當Pod被創建后就處於Pending狀態,等待調度器對其進行調度;調度的主要目的也是為這些Pending的Pod尋找最優的資源
  • Allocated: 當Pod被分配空閑資源,但是還沒有向kube-apiserver發送調度決策時,Pod處於Allocated狀態。 Allocated狀態僅存在於調度周期內部,用於記錄Pod和資源分配情況。當作業滿足啟動條件時 (e.g. 滿足minMember),會向kube-apiserver提交調度決策。如果本輪調度周期內無法提交調度決策,由狀態會回滾為Pending狀態。
  • Pipelined: 該狀態與Allocated狀態相似,區別在於處於該狀態的Pod分配到的資源為正在被釋放的資源 (Releasing)。該狀態主要用於等待被搶佔的資源釋放。該狀態是調度周期中的狀態,不會更新到kube-apiserver以減少通信,節省kube-apiserver的qps。
  • Binding: 當作業滿足啟動條件時,調度器會向kube-apiserver提交調度決策,在kube-apiserver返回最終狀態之前,Pod一直處於Binding狀態。該狀態也保存在調度器的Cache之中,因此跨調度周期有效。
  • Bound: 當作業的調度決策在kube-apiserver確認后,該Pod即為Bound狀態。
  • Releasing: Pod等待被刪除時即為Releasing狀態。
  • Running, Failed, Succeeded, Unknown: 與Pod的現有含義一致。

狀態之間根據不同的操作進行轉換,見下圖。

Pod的這些狀態為調度器提供了更多優化的可能。例如,當進行Pod驅逐時,驅逐在Binding和Bound狀態的Pod要比較驅逐Running狀態的Pod的代價要小 (思考:還有其它狀態的Pod可以驅逐嗎?);並且狀態都是記錄在Volcano調度內部,減少了與kube-apiserver的通信。但目前Volcano調度器僅使用了狀態的部分功能,比如現在的preemption/reclaim僅會驅逐Running狀態下的Pod;這主要是由於分佈式系統中很難做到完全的狀態同步,在驅逐Binding和Bound狀態的Pod會有很多的狀態競爭。

Volcano調度實現

Volcano調度器在支持上面這些主要場景時,分別使用了action和plugin兩級插件。總體來講,帶有動作屬性的功能,一般需要引入 action 插件;帶有選擇 (包括排序) 屬性的功能,一般使用 plugin 插件。因此,這些常見場景中,fair-sharing、queue、co-scheduling都通過plugin機制來實現:都帶有選擇屬性,比如“哪些作業應該被優先調度”;而preemption、reclaim、backfill、reserve 則通過 action 機制來實現:都帶有動作屬性,比如“作業A 搶佔 作業B”。這裏需要注意的是,action 與 plugin 一定是一同工作的;fair-sharing 這些 plugin 是藉助 allocate 發展作用,而 preemption 在創建新的 action 后,同樣需要 plugin 來選擇哪些作業應該被搶佔。這裏通過job-based fairness (DRF) 和 preempt 兩個功能的實現來介紹action 和 plugin 兩種插件機制的使用,其它功能類似:

  • Job-based Fairness (DRF): 目前的公平調度是基於DRF,並通過 plugin 插件來實現。在 OpenSession 中會先計算每個作業的 dominant resource和每個作業share的初始值;然後註冊 JobOrderFn回調函數,JobOrderFn 中接收兩個作業對象,並根據對像的 dominant resource 的 share值對作業進行排序;同時註冊EventHandler, 當Pod被分配或搶佔資源時,drf根據相應的作業及資源信息動態更新share值。

其它插件的實現方案也基本相似,在OpenSession中註冊相應的回調,例如 JobOrderFn, TaskOrderFn,調度器會根據回調函數的結果決定如何分配資源,並通過EventHandler來更新插件內的調度數。

  • Preemption: preempt是在allocate之後的一個action,它會為“高”優先級的Pending作業選取一個或多個“低”優先級的作業進行驅逐。由於搶佔的動作與分配的動作不一致,因此新創建了preempt action來處理相應的邏輯;同時,在選取高低優先級的作業時,preempt action還是依賴相應的plugin插件來實現。其它動作插件的實現方式也類似,即根據需要創建整體的流程;將帶有選擇屬性的問題轉換為算法插件。

6月4日晚20:00-21:00,Volcano/kube-batch 創始人在線授課,不僅傳授Volcano架構原理,還告訴你更多應用落地場景,戳鏈接免費觀看。

點擊關注,第一時間了解華為雲新鮮技術~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家