1. 程式人生 > >排程框架學習筆記(3)—— 叢集排程框架的架構演進過程

排程框架學習筆記(3)—— 叢集排程框架的架構演進過程

本章是 The evolution of cluster scheduler architectures 文章的學習筆記。這篇文章討論了這些年排程架構是如何發展的以及為什麼會這樣發展。

首先介紹一下這篇文章的作者:Malte Schwarzkopf,他目前在 MITPDOS實驗室 作博士後,說起作者的這個名字可能有點陌生,但是提起 Google 的叢集管理系統 Omega 應該很多人都知道,Omega 這篇文章,就是Malte 在谷歌實習時發表的。

2016 年他和 Ionel Gog 一起在 OSDI 上發表了一篇文章:《Firmament: fast, centralized cluster scheduling at scale》

,這份工作也是和谷歌一起合作的,目前Kubernetes也開始擁抱這個工作。

這篇文章討論了這些年排程架構是如何發展的以及為什麼會這樣發展。圖一展示了叢集排程的不同方法:其中灰色的方塊對應一個機器,不同顏色的圓圈代表不同的任務,有“S”標誌的圓角矩形代表排程器(這個圖簡化了一些,實際上,每臺機器執行多個任務,許多排程器適合多個資源緯度的任務,而不是簡單的slots),箭頭代表排程器決定的作業放置位置,三種顏色代表不同的工作負載(如網站服務、批量分析和機器學習)。

1545754113511

3.1 中心化排程框架

許多叢集排程框架,例如大量高效能運算(high-performance computing,HPC)排程器、

Borg 排程器、各種早期的Hadoop排程器和Kubernetes排程器都是中心化設計的排程框架。單一的排程程序在一臺機器上執行(例如Hadoop V1的JobTracker、Kubernetes的kube-scheduler),排程器負責將任務指派給叢集內的機器。在中心化排程框架下,所有的工作負載都是由一個排程器來處理,所有的作業都通過相同的排程邏輯來處理(如圖)。這種架構很簡單並且統一,在這個基礎上發展出了許多複雜的排程器。比如Paragon排程器和Quasar排程器,它們使用機器學習的方法來避免負載之間因互相競爭資源而產生的干擾。

1545754150046

現在大部分的叢集都執行著不同型別的應用(相反,如Hadoop MapReduce的早期作業)。然而,維護一個處理混合負載的單一排程器是一個很棘手的問題,原因如下:

  1. 希望排程器能區別處理長期執行的作業和批處理作業,這是一個合理的請求。
  2. 因為不同的應用有不同的需求,若要全部滿足其需求則需要不斷在排程器中增加特性,這樣增加了它的邏輯複雜度和部署難度。
  3. 排程器處理作業的順序變成了一個問題:佇列效應(例如頭阻塞:head-of-line blocking)和作業積壓是一個問題,除非在設計排程器時非常小心。

總之,這些聽起來是工程師的噩夢,排程器維護者會不斷收到往排程器中新增特性要求的清單。

3.2 兩級排程架構

兩級排程框架通過將資源排程和作業排程分開的方式來解決這個問題。兩級排程允許根據特定的應用來定做不同的作業排程邏輯,並同時保留了不同作業之間共享叢集資源的特性。Mesos叢集管理系統首先使用了兩級排程的方法,Yarn則支援其有限的版本。在Mesos中,資源是主動被提供給應用層的排程器來使用的(排程器可以從下層提供的資源中進行選擇),而Yarn則是由應用層來請求資源(並且接受被分配的資源)。如圖所示,適用於特定負載的排程器(S0-S2)與資源管理器進行互動,資源管理器則為每個負載動態劃分叢集的資源。這是一個非常靈活的方式,它允許針對特定負載來自定義排程策略。

1545754188364

但是,兩級排程框架也有一些問題。應用層排程器無法看到所有的資源,也就是說,它們沒有全域性視角,無法看到作業可以被放到哪些機器上執行。相反,它們只能看到資源管理器主動提供的資源(Mesos)或者資源管理器分配給應用(Yarn)的部分資源。這樣的設計有幾點缺點:

  1. 高優先順序搶佔(高優先順序作業會踢走低優先順序作業)會變得很難實現。在基於 offer 的模式下,被執行中作業所佔用的資源對上層排程器是不可見的;在基於 request 的模式下,底層的資源管理器必須能理解搶佔的策略(這可能與應用程式有關)。
  2. 排程器無法考慮到因其他執行的工作負載造成的干擾可能影響到資源的質量(比如“吵鬧的鄰居”佔據了 I/O 頻寬),因為排程器無法看到它們。
  3. 應用特定的排程器對底層資源的很多不同方面很關心,但是它們獲得資源的唯一方法就是通過資源管理器提供的 offer/request 介面,這個介面很容易變得非常複雜。

3.3 共享狀態排程架構

共享狀態排程通過半分散式的模式來解決這個問題,在這種模式下應用層的每個排程器都擁有一份叢集狀態的副本,並且排程器會獨立地對叢集狀態副本進行更新,如圖所示。一旦本地的狀態副本產生了變化,排程器會發佈一個事務去更新整個叢集的狀態,有時候因另外一個排程器同時釋出了一個衝突的事務時,事務更新有可能失敗。

1545754229408

在共享狀態排程的框架中,最著名的是Google的Omega、Microsoft的Apollo,以及Hashicorp的Nomad容器排程器。所有的這些都是使用一種方法實現共享狀態排程,就是Omega中的“cell state”、Apollo的“resource monitor”以及Nomad中的“plan queue”。Apollo跟其他兩個排程框架不同之處在於其共享狀態是隻讀的,排程事務是直接提交到叢集中的機器上,機器自己會檢查衝突,來決定是接受還是拒絕這個變化,這使得Apollo即使在共享狀態暫時不可用的情況下也可以執行。

邏輯上的共享狀態排程架構也可以不通過將整個叢集的狀態分佈在其他地方來實現,這種方式(有點像Apollo做的)中,每臺機器維護其自己的狀態併發送更新的請求到其他對該節點感興趣的代理,比如排程器、裝置健康監控器和資源監控系統等。每個物理裝置的本地狀態都成為了整個叢集的共享狀態的分片之一。

然而,共享狀態排程架構也有一些缺點,它必須工作在有穩定資訊的情況下(這點跟中心化排程器不同),在叢集資源的競爭度很高的情況下有可能造成排程器的效能下降(儘管其他框架也有可能出現這種情況)。

3.4 全分散式架構

全分散式架構更加去中心化:排程器之間根本沒有任何的協調,並且使用很多各自獨立的排程器來處理不同的負載,如圖所示。每個排程器都作用在自己本地(部分或者經常過時的)叢集狀態資訊。在分散式排程架構下,作業可以提交給任意的排程器,並且每個排程器可以將作業傳送到叢集中任何的節點上執行。與兩級排程排程框架不同的是,每個排程器並沒有負責的分割槽,相反的是,全域性排程和資源劃分都是服從統計和隨機分佈的,與共享狀態排程架構有些相似,但是沒有中央控制。

1545754299836

儘管全分散式排程架構的概念(多個隨機選擇)是從1996年出現的,現代意義上的分散式排程應該是從Sparrow論文開始的。Sparrow論文的關鍵是它假設叢集上任務週期都會變的越來越短,這點是以當時一個討論作為支撐的:細粒度的任務有很多的優勢。因此作者假設作業會變得越來越多,這意味著排程器必須支援更高決策的吞吐量,而單一的排程器並不能支援如此高的吞吐量(假設每秒有上百萬個任務),因此Sparrow將這些負載分散到很多排程器上。

這個實現的意義重大:缺少中央控制在理論上很吸引人,並且非常合適某些負載,我們會在後面的連載中進行討論。目前,我們注意到因為分散式排程器是不協調的,它相對於中心化排程、兩級排程或共享狀態排程擁有更簡單的邏輯,例如:

  1. 分散式排程器是基於簡單的“slot”概念,將每臺機器分成n個標準的“slot”,並放置n個並行作業,這簡化了任務的資源需求不統一的事實。
  2. 它使用了擁有簡單服務規則的worker-side佇列(例如,Sparrow中的FIFO規則),這樣限制了排程器的靈活性,因為排程器只能選擇將作業放置在哪臺裝置的佇列上。
  3. 分散式排程器很難執行全域性不變數(例如公平策略和嚴格的優先順序優先),因為它沒有中央控制。
  4. 因為分散式排程器是基於最少知識做出快速決策而設計,它無法支援或承擔複雜或特定應用的排程策略,例如,避免任務之間的相互干擾對分散式排程來說很困難。

3.5 混合式排程架構

混合式排程架構是最近(學術界提出的)提出的解決方法,它的出現是為了解決全分散式架構的缺點,它結合了中心化排程和共享狀態的設計。這種方式例如TarcilMercuryHawk一般有兩條排程路徑,一條是為部分負載設計的分散式排程(例如非常短的作業或者低優先順序的批作業),另外一條是中心式作業排程來處理剩下的負載,如圖1e所示。混合排程器的每個組成部分的行為與上述描述的部分架構相同。實際上,據我所知,目前還沒有真正的混合排程器應用於生產環節當中。

1545754338254

3.6 小結

對不同調度器架構的相對優缺點的討論並不只是學術探討,儘管它自然圍繞著研究論文。從工業界角度對於Borg、Mesos和Omega論文的深入討論可以參見Andrew Wang的博文。此外,很多以上討論的系統都已經部署到大型企業的生產系統中了(比如Microsoft的Apollo、Google的Borg、Apple的Mesos),反過來這些系統激勵了其他可用於開源的專案。

如今,很多叢集執行容器化的負載,因此有一系列基於容器的框架(Orchestration Frameworks)出現,它們與Google和其他稱為“叢集管理系統”的很相似。然而,很少有關於這些排程器的框架和設計原則的詳細討論,它們更多的是集中於面向使用者排程的API(例如這篇Armand Grillet的報道,文中比較了Docker Swarm、Mesos/Marathon和Kubernetes的預設排程器),然而很多客戶既不懂不同調度器的區別,也不知道哪個更適合自己的應用。

圖2展示了一部分開源框架的概況,包括它們的結構和排程器所支援的功能。在圖表的最底端,也包括Google和Microsoft沒有開源的系統作為參考。資源粒度(Resource Granularity)這一列展示了排程器是分配作業給固定大小的slots,還是按照作業多維度的資源需求來分配的(例如CPU、記憶體、磁碟IO頻寬、網路頻寬等)。

1545754379941

決定使用哪個排程框架主要的一點就是看叢集中是否執行一個異構(例如混合的)負載。例如一個前端服務(例如負載均衡或memcached)和批量資料分析作業(例如MapReduce或spark)相結合的生產環境,這種組合有利於提高系統的資源利用率,但是不同的應用對排程的需求有所不同。在作業混部的情況下,中心化排程可能導致任務的次優分配,因為不能基於單個應用進行邏輯的多樣化處理,因此在這種情況下,兩級排程和共享狀態排程可能更加合適。

大多數面向使用者服務的負載執行在資源能滿足峰值需求的容器中,但是實際上這些資源都是過度分配的,在這種情況下,能有機會降低給低優先順序負載過多分配資源(能繼續保證負載的QoS)對提高叢集的效率是非常關鍵的。儘管kubernetes擁有相對比較成熟的方案,Mesos是目前唯一支援這種過多分配資源的開源系統。我們期待未來在這個方面有更多的工作,因為根據Google的Borg叢集來看很多叢集的利用率依然低於60-70%。在後續的文章中,我們將關注資源預估、過度分配和有效提高機器的資源利用率。

最後,特定的分析和OLAP應用(例如Dremel或者SparkSQL Queries)會從全分散式排程器受益,然而,全分散式排程器(如Sparrow)有嚴格的功能設定,因此當叢集的負載是同構(比如所有作業的執行時間是大概相同的)、配置時間短(也就是任務能被排程到長時間執行的worker上,例如MapReduce作業在YARN中執行)、任務通量高(大部分排程的決定必須能在短時間內做出)時非常合適。我們將在接下來的文章中討論這些條件,並且討論為什麼全分散式排程器和混合式排程器中的分散式元件只對這些應用有效。現在,我們可以證明分散式排程比其他排程框架更加簡單,但是不支援多維度的資源、過度分配和重新排程。

總之,圖2中的表格表明對於開源的排程框架依舊有一段路要走,直到它們能匹配一些高階的配置。可以從以下幾個方面來採取行動:功能缺失、資源利用率低、作業的效能不可測和“吵鬧的鄰居”降低效率,並且需要將elaborate hacks加入到排程器中來支援使用者的需要。

然而,這裡有一些好訊息:儘管今天還有很多叢集仍然使用中心化排程,但是大部分已經開始遷移到更靈活的設計中。Kubernetes今天已經可以支援排程器外掛(kube-scheduler pod可以被其他相容排程pod的API所替代),更多排程器從1.2版本開始支援“擴充套件器”來提供定製化策略。據我瞭解,Docker Swarm在未來可能也會支援排程器外掛。

附錄:參考資料

叢集排程框架的架構演進過程