999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

SlurmX:基于Slurm使用面向對象設計方法重構的任務調度系統*

2022-09-21 08:36:30溫瑞林馬銀萍王政丹向廣宇付振新
計算機工程與科學 2022年9期
關鍵詞:資源信息

溫瑞林,樊 春,馬銀萍,王政丹,向廣宇 ,付振新

(1.北京大學信息科學技術學院,北京 100871;2.北京大學計算中心,北京 100871;3.北京大學國家生物醫學成像科學中心,北京 100871;4.鵬城實驗室,廣東 深圳 518055;5.北京大學軟件與微電子學院,北京 102600)

1 引言

Slurm[1]是一個在生產環境中廣泛使用的任務調度系統。Slurm的運行效率很高,但是當對其進行功能擴展時,由于Slurm代碼使用的是抽象能力較低的C語言且代碼規范不太嚴謹等原因,Slurm的代碼耦合度高、維護時間成本較大,添加新功能的效率也較低。因此,本文將Slurm的現有架構進行重構、解耦,使用具備較高抽象能力的C++進行重新實現,從而降低新功能的開發和維護成本,并基于此提出了一個新的任務調度系統SlurmX。

在SlurmX的設計過程中,本文參考了同樣使用C++語言編程,并且采用面向對象方法實現架構和組件設計的高性能計算系統HTCondor[2]的一些設計思路,同時也遵循了Slurm的原有功能和程序邏輯。

本文將先對Slurm的功能和SlurmX的需求進行分析;再對SlurmX進行系統架構設計和具體的內部模塊設計;最后對本文進行了總結,探討了未來改進方向。

2 SlurmX的需求及功能分析

2.1 用戶界面及接口使用需求

該資源調度系統要面向進行高性能計算的用戶,假定用戶具備一定程度的計算機知識,可以通過遠程終端使用命令行操作該軟件。因此,該資源調度系統除資源使用情況概覽等部分場景外,僅需提供命令行操作接口。

本文提供如下幾種命令行接口:

(1)提交單個計算任務的交互式接口。通過該接口,用戶可以實時提交計算任務,指定任務相關參數和計算資源需求,并且該任務以交互方式運行,用戶可以實時觀察到該計算任務在遠程執行節點上的輸出。同時,用戶也可以通過該接口對計算任務隨時執行終止操作。

(2)提交批量計算任務的非交互式接口。通過該接口,用戶可以通過編寫一個帶有多個計算任務的相關參數、計算資源需求以及各個任務之間依賴關系的配置文件,批量提交計算任務。這些計算任務以非交互方式運行,其數據會被轉存到相應文件,用戶可以通過查看這些文件的內容獲取這些計算任務的輸出內容。

(3)查詢計算任務和節點狀態等信息的接口。由于存在第(2)類非交互式命令行接口,因此需要有另外一個提供計算任務隊列和執行狀態查詢的命令行接口。同時,注意到除了計算任務的查詢接口之外,還有許多其他信息需要查詢,如節點當前工作狀態、資源使用情況和節點健康狀態等。為了防止命令行接口出現碎片化情況,本文對這些查詢接口統一進行了設計和實現。圖1描述了SlurmX的用例圖。

Figure 1 User case diagram of SlurmX圖1 SlurmX用例圖

2.2 可靠性需求

由于是在集群環境下,數量龐大的服務器集群中,某些節點在長時間工作之后不可避免地會出現不可用的情況。這些不可用的情況有可能是由于該節點內部的硬件出現物理故障導致的,如磁盤出現壞道或網卡故障;也有可能是由于外部環境的影響導致的,如外部網絡故障。當系統部分節點功能失效的情況出現時,該集群調度系統應當可以持續正常工作,并對這些故障做出妥當的處理;對于現有的正在非故障節點之上運行的計算任務,不應該出現任何可見的干擾;對于新提交的計算任務請求,應當能正確調度到非故障節點上運行;對于該資源調度系統的管理員,應當以合適的方式發出通知。

同時,對于臨時性故障節點,在可恢復的情況下,為了性能效率考慮,資源調度系統的控制器應當盡量對現存的任務保持繼續運行狀態,而不是重新啟動。

2.3 功能需求

下面描述命令行接口之外的具體功能,該資源調度系統在命令行接口的后端側需提供如下功能:

(1)該資源調度系統需具備嚴格的資源限制能力,即假設用戶不可信,可能會嘗試資源逃逸,該資源調度系統提供的資源限制能力應該可以防止這種情況的發生。

(2)該資源調度系統需提供多種資源調度算法,使得大量的計算任務可以被批量提交和批量調度。本文希望通過這些調度算法使集群中的各種計算資源得到高利用率。

(3)該資源調度系統需提供對于通用硬件資源的分配能力,如GPU、InfiniBand網卡和專用硬件加速器等。除了通用的CPU、內存資源之外,本文希望該資源調度系統能對那些專有硬件提供支持,對用戶提供統一的分配接口。同時,本文還希望該資源調度系統具備一定的可擴展性,對于未來新的硬件,可以通過編寫附加代碼或是提供動態鏈接庫的方式對其提供支持。

3 系統架構設計

3.1 主要組件

由于SlurmX所需實現的功能十分繁雜,本文僅抽出其中3個最重要的組件來闡明SlurmX中的架構設計:

(1)SlurmXd。該組件運行在計算節點之上,負責具體計算任務的生命周期管理、任務的I/O輸出轉發及資源隔離。其中,采用Linux提供的內核基礎設施cgroups實現資源控制;采用LibEvent框架提供的事件循環實現各種信號、進程I/O的處理。

(2)SlurmCtlXd。該組件運行在集群的控制節點之上,負責集群節點生命周期的管理、任務隊列的調度及管理、節點資源分配和前端SrunX發來的計算任務相關請求處理。

(3)SrunX。該組件運行在用戶節點之上,負責處理用戶計算任務需求輸入,并向SlurmCtlXd節點進行資源請求,轉發運行在SlurmXd節點上的軟件輸出。

3.2 組件間通信協議及交互流程

各個組件使用遠程過程調用RPC(Remote Process Call)在自定義的通信協議上進行通信。圖2給出了SlurmX各組件之間交互關系的可視化形式。

Figure 2 Interaction among the components of SlurmX圖2 SlurmX各組件之間交互關系

3.2.1 SrunX與SlurmCtlXd之間的通信協議及交互流程

SrunX首先接受用戶任務信息輸入。其中,任務信息包括所需要分配的CPU核數、內存大小、可執行路徑和命令行參數。SrunX將其所需要分配的資源信息打包之后,發送至SlurmCtlXd。SlurmCtlXd返回分配結果,如果分配成功,回復中會包含對應的SlurmXd節點標識符和所分配資源對應的Token(唯一標識符);如果分配失敗,會返回失敗原因。

3.2.2 SrunX與SlurmXd之間的通信協議及交互流程

當SrunX向SlurmCtlXd請求分配資源成功,取得所分配資源的Token后,SrunX會根據SlurmXd節點標識符連接對應的SlurmXd節點,發送任務信息和所分配資源的Token。

SlurmXd在收到任務信息并檢驗資源Token的合法性之后,開始嘗試運行任務。如果運行失敗,SlurmXd向SrunX返回任務失敗原因,SrunX向用戶顯示相關信息,結束運行,同時SlurmXd也結束該任務的處理流程;如果任務運行成功,SlurmXd開始持續向SrunX轉發任務的輸出信息,直到任務結束。當任務運行結束之后,SlurmXd會收集任務的結束信息,將其返回給SrunX,SrunX在接收到任務結束信息后,向用戶顯示相關信息,結束運行。

由于轉發所運行任務的輸出信息需要流式協議,因此在SrunX側和SlurmXd側都需要一個實現上述功能的狀態機。

3.2.3 SlurmXd與SlurmCtlXd之間的通信協議及交互流程

SlurmCtlXd在確認SrunX請求的資源可分配之后,選擇指定的SlurmXd節點分配資源并生成資源Token后,將該Token下發至SlurmXd節點。

由于SlurmXd承擔了讓該資源Token失效的責任,因此SlurmXd需要監控任務狀態。當任務因為任何原因不再運行后,SlurmXd需要通知SlurmCtlXd該Token已經失效。

同時,SlurmXd在啟動之后,需要主動向SlurmCtlXd發送注冊請求,注冊請求中包含SlurmXd節點的可分配資源等信息。SlurmCtlXd在收到來自SlurmXd的注冊請求之后,會嘗試與SlurmXd建立連接,并通過此鏈接的連接狀態檢測SlurmXd節點的健康狀態。

4 組件詳細設計

本節主要介紹SlurmXd和SlurmCtlXd組件內部的詳細設計。由于SrunX本質上是一個簡單的客戶端,故其內部設計略過不表。

4.1 SlurmCtlXd

4.1.1 內部各組件概覽

SlurmCtlXd內部包含以下組件:

(1)XdNodeKeeper。該組件統一管理所有SlurmXd計算節點的連接情況。

(2)XdNodeMetaContainer。該組件統一維護所有SlurmXd計算節點的元數據信息(如任務列表、資源使用情況等),由于此類信息有著很高的查詢和更新頻率,在大規模任務調度時,會由于強競爭導致運行效率下降,因此本文專門抽象了一個類,對其進行高并發和查詢方面的優化。

(3)gRPC Server。在目前的實現中,本文采用了Google的gRPC[3]框架作為底層的通信框架,同時為了避免與gRPC框架過高的耦合度,本文實現了一個gRPC Server類,將gRPC框架細節封裝在該類中。

(4)GarbageCollector。由于C++不是一門帶有Garbage Collection(無效內存資源回收)的語言,因此需要專門的類來處理運行過程中臨時對象的釋放。這個類中含有一個固定線程,通過多線程并發回收的方式降低延遲。

SlurmCtlXd各組件之間的協作情況如圖3所示,XdNodeKeeper通過暴露的外部接口,在SlurmXd節點狀態更新時,通知XdNodeMetaContainer修改節點數據,gRPC Server代理了所有外部請求的處理,對于增加新SlurmXd節點的請求,gRPC Server將其轉發至XdNodeKeeper;對于其他請求中需要查詢SlurmXd節點數據的行為,則通過XdNodeMetaContainer查詢。XdNodeMetaContainer和XdNodeKeeper都通過GarbageCollector進行垃圾回收。

Figure 3 Component diagram of SlurmCtlXd圖3 SlurmCtlXd內部組件圖

4.1.2 XdNodeKeeper

作為資源調度系統的中心控制器,SlurmCtlXd最重要的功能之一便是監控作為計算節點的SlurmXd節點的健康狀態。在SlurmCtlXd接收到SlurmXd節點注冊請求的那一刻開始,SlurmCtlXd便需要向作為通信底層的gRPC框架注冊狀態監聽信息,通過底層的gRPC Channel的狀態,監測從發起鏈接到節點停止服務的SlurmXd全生命周期的狀態。

此部分實現繁雜,但是其邏輯上只包含了檢測SlurmX節點狀態的功能,因此本文參考HTCondor中的Master-Worker[4]模型,結合gRPC做出了如下設計:

SlurmCtlXd作為中心控制器,其關心的信息只有節點是否存活,即ALIVE和DEAD這2種狀態。但是,由于節點有可能由于網絡波動出現臨時性的鏈接中斷,考慮到節點注冊的高昂開銷,便引入了另外一個狀態TRANSIENT_FAILURE描述此種臨時性的鏈接中斷。

由于SlurmXd節點可能數量眾多(一般以百計算),本文需要對每一個SlurmXd節點進行狀態監控,但又不希望為每一個節點都分配一個線程來監聽引起狀態機變化的事件,這樣不僅會引入額外的同步開銷,而且不同線程之間同步代碼邏輯的編寫也要花費大量的時間。因此,本文采用了gRPC Channel提供的異步事件狀態監聽API:NotifyOnStateChange,從而可以在單線程中完成此項工作。NotifyOnStateChange通過一個用戶提供名稱為data的可修改參數標記所監聽的事件,在該資源調度系統的場景中,使用針對SlurmXd節點的狀態設計狀態機模型來對SlurmXd節點的狀態變化進行抽象,并在這個API中使用一個名稱為tag的變量來標記每個SlurmXd節點對應的狀態機。通過這個API,本文在一個監聽異步事件的線程中,通過所觸發事件對應的data參數來區分SlurmXd節點的身份。為了使代碼書寫具有良好的模塊性,根據本文場景,將SlurmXd狀態機分為2種類型,一種是正在建立連接的SlurmXd節點,本文將此類節點賦予一個類型tag:InitXd;另一種是已經建立連接的SlurmXd節點,本文將此類節點賦予一個類型tag:EstabXd。同時,還需要另外一個數據結構,用于記錄已經建立連接的EstabXd節點的編號以及當其連接臨時性失敗后進入TRANSIENT_FAILURE狀態時的重試次數等信息。因此,本文向NotifyOnStateChange提供的data參數由2部分組成,第1部分是類型tag,第2部分是保存編號和重試次數等信息的數據結構。

gRPC中用來對連接進行抽象的組件Channel的狀態(如圖4所示)有為IDLE(等待連接)、CONNECTING(正在連接中)、READY(連接已建立,可以在這個Channel上發送RPC請求)和TRANSIENT_FAILURE(連接中斷,臨時性失敗)4個狀態,但這并不符合上述3個狀態的需求。所以,本文需要針對上述3個狀態,編寫底層的狀態機處理邏輯,利用回調函數的形式轉換成上層需要的SlurmXd的狀態機。

Figure 4 State machine in XdNodeKeeper圖4 XdNodeKeeper狀態機

因此,本文針對gRPC Channel狀態變化,設計了圖4所示的狀態機,用來將該gRPC Channel的狀態機映射到SlurmXd節點的狀態機,使用4個回調函數NodeIsUp()、NodeRecovered()、NodeIsTempDown()和NodeIsDown()來驅動SlurmXd節點狀態機的狀態變化。在這4個回調函數被調用時,會傳遞包括該SlurmXd節點編號在內的相關信息給外部XdNodeKeeper的使用者,使其可以區分該狀態變化來自哪一個SlurmXd節點。

本文先給出該狀態機中各個圖形的含義。在圖5中描述了狀態及狀態轉移:狀態機當前在狀態B,前一個狀態是A,由A狀態到B狀態的狀態遷移是由Cond事件被觸發導致的,該狀態機現在執行Action動作。

Figure 5 Notation of the state diagram圖5 狀態機中圖形的表示方法

在描述了狀態機的圖形含義后,再來闡述該SlurmXd狀態機具體的實現細節。當XdNodeKeeper收到SlurmXd節點的注冊請求之后,XdNodeKeeper為該SlurmXd節點新建一個狀態機。

本文以圖4所示的左上角的實心黑圓作為起始狀態,其中,在向NotifyOnStateChange提供的data數據中,將Tag類型設置為InitXd,重試次數retry_count置為0,然后進入IDLE狀態。進入IDLE狀態后,嘗試向SlurmXd節點發起連接,此時gRPC Channel進入CONNECTING狀態。若SlurmXd節點因為端口僅單向開放等原因連接失敗,則該狀態機進入TRANSIENT_FAILURE狀態,此時SlurmXd狀態機將retry_count加1,并嘗試重連,再次進入CONNECTING狀態,如果重復連接N次(N為用戶設置的次數,默認為3)還是失敗,則狀態機進入結束狀態,由于此時Tag類型為InitXd,向注冊請求返回失敗信息,并釋放該狀態機相關資源。若SlurmXd節點連接成功,則該SlurmXd進入READY狀態,此時為該SlurmXd節點分配節點編號;將其Tag類型設置為EstabXd,表示該節點已建立連接;通知該SlurmXd節點的注冊者該節點已經成功注冊,建立連接;通過NodeIsUp()回調函數,向外部的XdNodeKeeper使用者(主要是下文的XdNodeMetaContainer)通知一個新的SlurmXd節點已經成功連接;將retry_count重新設置為0。

由上文論述可知,一個Tag類型為EstabXd的SlurmXd節點(即已建立連接節點)的起始狀態實際上是READY狀態。EstabXd狀態下的節點故障的處理邏輯和InitXd狀態下的處理邏輯類似,僅僅在回調通知函數上出現了一些變化,這是為了方便上層應用做更詳細的處理工作。

通過對gRPC Channel的狀態進行有針對性的狀態機設計,XdNodeKeeper將底層使用gRPC進行RPC調用和節點連接狀態檢測的繁雜實現細節成功封裝。如圖6所示,XdNodeKeeper對外只暴露了用來請求注冊新的SlurmXd節點的RegisterXdNode接口和設置前文所述的4個回調函數的接口,并通過這4個回調函數對外匯報節點變化狀態。通過極簡的接口暴露,XdNodeKeeper成功實現了與SlurmCtlXd其他組件的解耦,避免了在后期底層gRPC通信代碼發生更改時造成其他組件大規模的代碼改動。

Figure 6 Relationship between XdNodeKeeper and gRPC圖6 XdNodeKeeper與gRPC的關系

4.1.3 XdNodeMetaContainer

SlurmCtlXd中需要記錄所有SlurmXd節點的信息,這些信息包括:當前節點狀態、用來發起SlurmXd的RPC調用的gRPC stub以及該SlurmXd所有的資源信息、分配情況和該SlurmXd上所執行的所有任務信息。

這些信息面臨著大量的查詢和修改,因此,本文抽象出一個類,用于統一維護和保護這些信息。在SlurmCtlXd中,當SlurmXd節點狀態發生變化時,希望可以在最短的時間內對該節點狀態進行更新,使新舊信息更新的窗口期盡量縮短,后續到來的任務請求可以最快地按照更新后的節點狀態進行資源分配。

但是,由于節點信息繁雜,對這些節點信息進行更改的時間代價較大,如果按照傳統的讀寫鎖算法,無論該讀寫鎖是否選擇讀寫者公平實現,當寫者取得讀寫鎖的獨占權后,所有讀者都必須等待寫者完成后才可以開始臨界區數據的讀取,這種高昂的開銷在一個高并發系統上是不可接受的。因此,本文需要確保SlurmXd節點數據的更新不會中斷大量的節點數據查詢。

同時,當任務數量上升至萬級別后,這些任務的事件處理會帶來短時間內的大量的以萬甚至十萬計的SlurmXd節點數據查詢,考慮到現代CPU在Cache Line需要進行同步時時延差不多在100 ns左右[5],十萬級別的對同一互斥鎖的競爭就會產生秒級的延遲,因此本文要保證大量并發讀安全的同時降低競爭開銷。常用的讀寫鎖往往采用2個互斥鎖加上幾個條件變量實現,其開銷在臨界區小于毫秒級的時候,開銷并不比互斥鎖低,因此使用讀寫鎖在此場景下不但不會減小開銷,反而會增大開銷。

總結上述需求,本文用來維護SlurmXd節點相關數據的組件XdNodeMetaContainer需要滿足如下條件:

(1)在SlurmXd節點發生事件更新時,該事件后續對于節點數據的查詢能以最快的速度看到更新,不會被SlurmXd節點數據的更新阻塞。

(2)高度并行化的節點數據讀取不會導致嚴重的同步性能開銷。

經過對一些現有成熟技術的考察,如bRPC中的DoublyBufferedData[6],在XdNodeMetaContainer中,采用了雙緩沖加Thread-Local互斥量的方法。在該組件中,將SlurmXd的節點數據進行“雙拷貝”,分為前臺數據和后臺數據。當該組件進行初始化時,前臺數據和后臺數據都為空。當一個更新請求到來時,該組件先更新其后臺數據。此時,前臺數據仍可以被并發的查詢請求正常訪問,不會被后臺的數據更新阻塞,即和后臺的數據更新相互獨立。

同時,該組件會為所有產生數據讀取請求的進程創建一個Thread-Local(線程本地的)互斥量,而前臺的所有針對該數據結構的讀取請求都會對其所在線程的線程本地互斥量進行加鎖。由于該互斥量位于線程本地存儲空間內部,所以對該互斥量加鎖并不會產生任何競爭。對于一個不存在競爭,即不需要進行CPU的不同核心間Cache Line同步的互斥量,其開銷在50個CPU 指令周期左右,即17 ns左右[5],因此,當所有查詢線程共用一個互斥量時,在高強度并發訪問條件下,每次加鎖有100 ns左右的開銷[5],采用每線程一個線程本地互斥量的方法,有效地降低了時延,提高了性能。

在后臺數據更新完畢之后,該組件使用C++的atomic庫封裝的CPU原子操作對前后臺數據進行轉換。在該原子操作后,前臺數據為更新后的SlurmXd節點數據,后臺數據為還未更新的正在被現有針對該數據結構進行查詢的請求所使用的舊SlurmXd節點數據。因此,所有除現有正在進行的對該數據結構進行的查詢之外的后續新請求都會看到更新后的數據。唯一會產生阻塞等待的步驟,是在對后臺還未更新的舊數據進行更新之前,需要等待還在使用舊數據的所有請求完成。當所有使用舊數據的請求都結束之后,本文在此時對后臺的數據副本進行更新操作。更新完成后,前臺數據和后臺數據即完成了最終的統一,此時,一個對于該數據結構的修改操作才算完成。

由于讀取操作不會產生互斥鎖的競爭,因此該數據結構在對于讀取操作的多線程競爭保護上所花費的開銷可以不計。對于修改操作,由于對后臺數據可以立即進行修改,并且在修改之后后臺數據立刻與前臺數據互換,因此,修改操作對于所有并發的查詢讀取請求的同步要求只在前后臺數據切換后,需要所有進行新的讀取請求的CPU核心的Cache Line對該切換后的數據進行同步等待操作,無需中斷還在對未更新的新后臺數據進行查詢的請求或者是長時間等待。該數據結構設計的本質是根據該數據結構讀請求極多和寫請求極少的特點,通過犧牲對數據結構修改的性能,來有效提升對高并發讀取請求的性能。

4.1.4 GarbageCollector

從前述的2個組件XdNodeKeeper和XdNodeMetaContainer可以看到,這2個組件需要負責對SlurmXd狀態機和SlurmXd節點相關信息的分配和清理。為了保障用來記錄這些信息的內存不會發生泄漏,在該資源調度系統的實現中,采用了C++標準庫中的共享指針shared_ptr[7]來對這些分配的資源進行引用計數。當XdNodeKeeper、XdNodeMetaContainer和所有使用這些資源的請求都對某個資源進行了共享指針釋放之后,該資源的引用計數將下降為0,此時將釋放這些資源。但是,這些資源包含的信息十分繁雜,對于這些資源的分配和釋放清理都需要一定的時間開銷。考慮到所有SlurmXd節點的狀態機都在XdNodeKeeper的一個專有線程中進行維護,因此,本文不再處理該資源分配和釋放的工作,否則會影響到SlurmXd節點狀態信息更新的時效性。

通過GarbageCollector將所有資源清理的開銷全部從時延敏感的執行路徑中轉移了,這樣提高了整體的響應性能和任務吞吐量。

4.2 SlurmXd

本節主要介紹SlurmXd中資源控制組件CgroupManager、任務管理組件TaskManager及設備抽象類Devices和設備資源分配器DevicesAllocator的實現。

4.2.1 CgroupManager

除了調度任務的執行順序,資源調度系統最重要的一個作用是限制計算任務資源的使用,即任務使用的資源不能超過某一個系統或用戶限定的數值。

Linux 2.6.24引入了一個很重要的特性cgroups(control groups)[8]。cgroups是Linux內核中的一個組件,通過該組件可以從操作系統的層面對應用施加資源使用限制。

Linux的cgroups有2個版本:v1和v2。CgroupManager目前采用v1版本實現,v1版本的cgroups的高層結構如圖7所示。

Figure 7 Structure of cgroups圖7 cgroups架構

cgroups為系統中許多可控制的資源,如CPU、Memory,提供控制器,控制器還可以派生出多個子控制器(在圖7中為不同的cgroups hierarchy)。在Linux中,每個進程若是使用cgroups,在進程控制塊中有一個數據結構css_set[9]記錄該進程服從于哪些子系統控制器的管理。其中,多個進程可以和相同的css_set綁定,從而達成管理一個進程組的目的。

由于cgroups具備很高的配置靈活性,本文需要自己制定一些統一規則,將底層靈活的組件配置固化成一套可供上層組件便捷使用的抽象接口,以方便高層組件實現各種邏輯。

Figure 8 Abstraction model of cgroups圖8 cgroups的抽象模型

因此,本文對于CgroupManager制定了如下的規則和限制:CgroupManager組件在初始化時會在所有指定需要使用的控制器系統(如CPU、Memory)的對應根控制器下創建一個CgroupManager使用的專有層級,同時約定在所有子系統的該專有層級下子目錄結構是相同的。因此,本文實際上利用cgroups抽象出了一個具備不同層級結構,但是每個層級控制器相同的一個控制器系統層級結構。本文將這個抽象系統的根層級命名為CgroupManager Root Hierarchy。考慮該資源調度系統的實際場景,每個用戶會提交一個計算任務,同時用戶或者系統會對該任務施加資源限制條件。注意到這些計算任務之間實際為平級關系,因此,CgroupManager Root Hierarchy下只會具備多個平級的子層級,即不會具備子子層級,本文將這些子層級的單個實體命名為CgroupManager Leaf Hierarchy。

由上文所述可知,CgroupManager Leaf Hierarchy實際上是單個計算任務通過cgroups實現的一系列資源限制。圖8給出了cgroups的抽象模型。

cgroups不僅提供了操作系統內核層面對系統資源的使用限制,也提供了對資源使用情況的查詢能力。由于監控任務的各種資源使用情況也是該資源調度系統的重要功能,CgroupManager將cgroups底層資源的使用情況查詢接口進行了一定程度的封裝,對外提供了對資源的查詢功能。圖9描述了CgroupManager的類設計。通過該類,可以自由地對任務所使用的資源進行限制,例如將CPU限制在3個核心或是在任務所使用內存資源超過限制時由Linux的OOM Killer[10]將其終止。

Figure 9 CgroupManager class圖9 CgroupManager類

4.2.2 TaskManager

TaskManager是SlurmXd中承擔任務運行、任務管理和任務I/O重定向等功能的組件,是SlurmXd的核心組件。下面主要介紹該組件的設計和原理:

從上文的描述可以看出,TaskManager在運行時需要處理許多事件。這些事件包括但不限于:

(1)添加新任務的請求。

(2)轉發來自前端SrunX的中斷信號或輸入到正在SlurmXd節點上運行的任務中。

(3)將正在運行的任務產生的輸出轉發到前端SrunX。

(4)處理來自SlurmXd所在節點的結束信號SIGINT或SIGRTERM以及負責計算任務結束時的回收工作。

TaskManager在處理大量事件的同時,還需特別注意保護在TaskManager中維護的所有任務信息在可能的多線程執行環境中不會因為并發修改和訪問導致數據損毀,這就要求本文通過互斥量對相關的數據結構進行保護。

總結上文,有2個需求:一是可以便捷地處理大量事件;二是在處理大量事件的同時要注意對相關數據結構的并發保護。采用事件驅動模型可以處理上述需求。在事件驅動模型中,本文先將要監聽的事件添加到一個監聽列表,通過啟動一個專有線程,不斷地對這些事件進行輪詢,檢查事件是否已經發生,如果某個事件發生,則執行該事件對應的處理邏輯。同時,如果在某次輪詢中,多個事件同時發生,則在該線程中順序執行這些事件的處理邏輯。采用事件驅動模型的一個好處是,由于所有事件的處理邏輯實際上是串行執行的,因此不會存在多線程執行場景下需要實現很復雜同步邏輯的弊端。事件驅動模型的主要弊端在于,只有一個工作線程卻需要處理所有事件邏輯。針對本文需求,使用了LibEvent庫作為底層的事件通知庫。圖10描述了LibEvent的內部線程模型。

Figure 10 Internal threading model of LibEvent圖10 LibEvent內部線程模型

明確了所使用的執行模型后,接下來介紹TaskManager的具體執行流程。在TaskManager初始化時,先利用LibEvent提供的注冊事件API注冊如下所述的事件及其對應的處理邏輯:

(1)SIGINT信號事件。該信號由用戶輸入,當用戶在鍵盤上按下Ctrl+C或由其他軟件發送該信號時,表明用戶希望SlurmXd關閉。此時將不再接收任何新的任務請求,并向所有正在執行的任務下屬的進程組發送SIGINT信號,等待所有任務結束回收并執行相應的清理工作之后再退出。

(2)SIGCHLD信號事件。當一個計算任務結束之后,由于SlurmXd進程為計算任務中實際執行進程的父進程,SlurmXd會收到一個SIGCHLD信號,表明有計算任務已經結束。SlurmXd收到信號之后會解析程序的返回值并統計程序相關信息后將其統一返回給用戶前端執行程序SrunX,并由SrunX顯示這些信息,表明程序已經結束。

(3)創建新任務請求事件。當用戶通過SrunX發送任務信息和資源Token時,gRPC框架中對應的RPC請求處理邏輯會將該請求封裝成一個包含任務信息、輸出回調函數、任務結束回調函數和異步通知類的新任務請求結構體。本文規定由SrunX提交的任務信息必須包含如下信息:

①任務名稱;

②任務可執行路徑;

③任務參數;

④cgroups資源限制信息。

同時,為了達成轉發任務輸出的效果以及在任務結束時可以通知SrunX的目標,本文在新任務請求結構體中添加了輸出回調函數和任務結束回調函數。這2個回調函數可以由調用TaskManager中添加新任務接口的調用方設置,這樣設計的目的是為了保持和任務管理無關的邏輯與TaskManager解耦,即將涉及gRPC部分的代碼實現排除在TaskManager的代碼實現之外,從而保持代碼的可維護性。同時,SrunX也有可能以流的形式傳遞多種控制信息,因此本文在SrunX側和SlurmXd側都針對該邏輯實現了狀態機。

在實現中還有一個難點是使用TaskManager功能的類無法直接以同步方式調用LibEvent中的任務執行邏輯,這部分邏輯只有當事件觸發時才會被執行,因此,為了在同步函數調用中能以異步方式獲取新任務的添加結果,TaskManager采用了C++標準庫中的std::future和std::promise[11]來提供異步通知新任務添加結果的功能,并通過跨線程單生產者單消費者隊列進行新任務添加請求的傳遞,通過Linux提供eventfd來完成對新任務請求事件在LibEvent中的觸發。

(4)任務輸出事件。注意到該事件并未在TaskManager初始化時進行注冊,這是因為每個任務輸出事件必須和一個計算任務綁定,因此它是一種只有在生成新計算任務時才會注冊的動態事件。當計算任務有輸出產生時,該事件處理邏輯會調用與該計算任務所綁定的輸出回調函數,從而進入上文中所述的邏輯,將輸出轉發至SrunX。

基于上文所述的內容,SlurmXd中核心組件TaskManager的功能得以實現。

4.2.3 Devices類、DevicesAllocator類和專有設備的適配

該資源調度系統需要對各類資源進行分配,這些資源包括所有機器通用的資源,如CPU、內存和外置的專有硬件(如不同型號的顯卡和不同種類的網卡)。由于在不同的使用場景下設備種類是截然不同的,因此在實際應用場景中,很可能會出現場景變更一次,硬件變更一次的情況。而顯然該資源調度系統的使用者希望該系統能適配多種類型的硬件,以避免每當更換平臺時為適配新硬件對該資源調度系統的主體代碼進行大規模更改。

因此,在進行此部分功能的模塊設計時,需要考慮上文所述的使用者需求。當一個計算任務開始執行的時候,分配給該任務的各種硬件資源需要進行初始化。例如,通過上文設計的CgroupManager對CPU和內存資源進行限制,對通過PCIe接入的專有設備進行權限設置。當一個計算任務結束時,可能有相關設備資源需要清理或者重置,例如對GPU的功耗解除限制。同時,不同類型硬件的資源分配邏輯可能也不同,例如CPU或內存屬于可以進行細粒度分配的資源類型,而PCIe設備則不支持細粒度分配,因此二者需要根據不同的邏輯進行分配。

因此,本文參考Adapter設計模式[12]將設備資源抽象為Devices類,該類提供的主要方法有Prepare和Cleanup。Devices類表示統一類型的一個資源或者多個資源歸屬于一個計算任務。當其歸屬的計算任務執行前,會調用該計算任務所擁有的Devices類的Prepare方法,硬件資源相關的初始化代碼在該方法中。當其歸屬的計算任務結束后,會調用該計算任務所有擁有的Devices類的Cleanup方法,硬件資源相關的清理和釋放代碼在該方法中。

每一個Devices類對應一個DevicesAllocator類,該DevicesAllocator類提供的主要方法有Init、AllocateDevices和FreeDevices,其中,Init提供某個Devices類對應的專有硬件的初始化統計;AllocateDevices負責分配指定數量和特定子類型的某類型設備,返回對應的Devices類示例;FreeDevices負責釋放AllocateDevices所分配的資源。所有DevicesAllocator類的Init方法會在SlurmXd進行初始化時被調用,AllocateDevices在創建單個新的計算任務請求資源時被調用,FreeDevices在計算任務結束后會被調用。

Figure 11 Devices class and DevicesAllocator class圖11 Devices類和DevicesAllocator類

5 結束語

本文基于Slurm任務調度系統,通過引進面向對象的設計方法,對Slurm中的部分重要功能進行了抽象和模塊化,并對Slurm中原有的架構進行了重新設計。本文將基于上述工作設計及實現的任務調度系統命名為SlurmX。相對于Slurm原有的過程化實現,SlurmX在保障高性能的情況下,有效降低了代碼的復雜度和耦合度,提升了模塊化程度,在工程方面降低了后續維護和添加自定義功能的開發成本。同時,由于Slurm是一個已經歷經約二十年沉淀的項目,其功能繁復紛雜,SlurmX目前僅對Slurm中最為基礎和重要的功能進行了重構,仍有許多功能還有待重構和設計。目前,SlurmX整體系統還未定型,當整體架構定型、實現完善及詳細測試后將會開源,以方便感興趣的科研機構進行驗證和推廣。

猜你喜歡
資源信息
讓有限的“資源”更有效
基礎教育資源展示
一樣的資源,不一樣的收獲
資源回收
訂閱信息
中華手工(2017年2期)2017-06-06 23:00:31
資源再生 歡迎訂閱
資源再生(2017年3期)2017-06-01 12:20:59
展會信息
中外會展(2014年4期)2014-11-27 07:46:46
對你有用的“錢”在資源
職場(2009年4期)2009-01-01 00:00:00
信息
建筑創作(2001年3期)2001-08-22 18:48:14
健康信息
祝您健康(1987年3期)1987-12-30 09:52:32
主站蜘蛛池模板: 精品国产女同疯狂摩擦2| 久操线在视频在线观看| 成人字幕网视频在线观看| 国产精品午夜电影| 一级在线毛片| 欧美一区二区三区国产精品| 99热最新网址| 免费观看亚洲人成网站| 亚洲午夜天堂| 亚洲最大福利网站| 在线免费a视频| 久久精品人人做人人爽| 精品一区国产精品| 国产一二三区视频| 国产91无码福利在线| 国产理论最新国产精品视频| 日本在线国产| 日本尹人综合香蕉在线观看| 亚洲精品在线91| 国产青榴视频| 97se亚洲综合| 91精品国产一区| 亚洲中文字幕久久无码精品A| 成人无码区免费视频网站蜜臀| 久久亚洲精少妇毛片午夜无码| 女人18一级毛片免费观看| 日韩欧美成人高清在线观看| 色悠久久久| 欧美日韩午夜| 亚洲视屏在线观看| 午夜福利网址| 国产91小视频| 国产大片喷水在线在线视频| 亚洲综合精品第一页| 色老二精品视频在线观看| 91免费精品国偷自产在线在线| 国内精品自在自线视频香蕉| 久久久久亚洲AV成人网站软件| 久久公开视频| 2022国产91精品久久久久久| 欧美成人手机在线观看网址| 日韩在线1| 天天综合网站| 在线视频97| a欧美在线| 青青青国产在线播放| 91国内外精品自在线播放| 亚洲精品国产日韩无码AV永久免费网| 欧美啪啪网| 久久免费看片| 在线网站18禁| 欧美成a人片在线观看| 中文字幕在线播放不卡| 国内精品久久人妻无码大片高| 日韩无码视频播放| 国产区免费精品视频| 第一区免费在线观看| 亚欧乱色视频网站大全| 亚洲欧洲日产国产无码AV| 国产免费久久精品44| a毛片在线免费观看| 亚洲精品麻豆| 99久久无色码中文字幕| 亚欧美国产综合| 欧美日本二区| 青青草原国产免费av观看| 欧美国产菊爆免费观看| 国产精品无码久久久久久| 日本亚洲欧美在线| 在线精品视频成人网| 尤物精品视频一区二区三区| 亚洲综合一区国产精品| 黑色丝袜高跟国产在线91| 久久久久久尹人网香蕉| 亚洲看片网| 奇米精品一区二区三区在线观看| 中文成人在线| 综合人妻久久一区二区精品| 亚洲天堂2014| 91精品视频网站| 欧美成人一级| 成人免费午间影院在线观看|