今天咱們來討論分佈式資源調度。算法
咱們知道,計算機的出現很大程度上是爲了分擔人類的工做的。因此,整個計算機體系架構的演化的過程,都離不開對任務與資源這兩個因素的考慮。如何利用最少的資源,運行最多的任務,且耗時最短,這是一直以來伴隨咱們以及科學家的難題。對於單機系統來講,從最先的單道程序設計技術、到多道程序設計技術、到如今的多核並行架構,解決方案正在逐步進化,也就是咱們最直觀的感覺:計算機處理任務變快了。數據庫
咱們能夠類比一下操做系統的概念。相比於分佈式資源調度,操做系統其實就是一種微觀上的資源調度。咱們把任務與任務相關的一系列上下文(包括程序代碼與數據),通通抽象爲進程。進程就是任務。在單核CPU架構下,因爲只有一個CPU核,因此咱們只能同時對一個任務進行處理。
可是,咱們的任務數量不僅會有1個,而是會遠遠超出CPU的數量,即「僧多粥少」的局面,因此,操做系統的進程調度算法出現了,好比時間片輪轉調度算法,即一段時間內,CPU快速在多個任務之間快速切換、交替執行,故對每一個任務內部來講,好像本身在獨佔CPU同樣,這就是所謂的併發。除此以外,還有高優先級、高響應比、多級反饋隊列調度等等任務調度算法,都在力圖在單核CPU基礎上解決這個問題。可是,咱們必定不會知足,爲了追求更高程度的併發,即在同一時刻容許多個任務同時運行。因此,多核CPU就這樣誕生了,即實現了所謂的並行。那麼同理,分佈式系統也一樣須要這種資源與任務的調度機制,來協調資源與任務之間的關係。
分佈式系統存在的意義之一,就是解決單體架構執行任務時的性能瓶頸,因此,咱們找來了一堆機器,來分擔原來一臺機器上的計算任務。可是,資源是多了,可是咱們要如何利用呢?這裏面就涉及到資源如何公平公正的分給每個計算任務,讓整個集羣合理的利用硬件資源,短時、高效、公平的完成一系列的計算任務,而不至於某個任務被餓死或者撐死。因此,須要一個宏觀上的「操做系統」,來合理的將無窮多個計算任務,分配到m個集羣節點的計算資源上去執行。這,就是爲何須要分佈式資源調度機制。segmentfault
對於操做系統進程調度來講,資源只有一份,那就是當前操做系統所在的計算機硬件資源;而任務有不少,資源:任務 = 1:N的關係,操做系統在進行任務調度以前,只須要收集它所在的計算機的硬件資源便可。而對於一個分佈式系統中的集羣,計算資源分佈在多個節點上,任務仍是有不少,他們之間是M:N的關係。因此,分佈式系統的工做稍微複雜些,它須要收集全部節點上的資源信息而非僅僅一個節點,而後對全部收集來的資源信息作一個統籌規劃。服務器
若是讓咱們本身設計一個調度系統,咱們天然會想到以前講過的「分佈式經典架構」中的集中式架構,由一個節點全權負責資源分配與任務調度。這,其實就是單體調度。單體調度模塊稱爲「Scheduler」或「單體調度器」。全部的資源請求和任務調度都經過這個中心節點來進行。集中式調度器的常見模型,以下圖所示。:
咱們看到,master節點會收集每一個節點的節點狀態並交給master中的cluster state模塊。這個節點狀態就是指集羣的計算資源的分佈狀況,而這個cluster state模塊通常是一種內存數據庫。而後,橙色方框Scheduling logic會到cluster state中查詢集羣資源的分佈狀況,而後根據分佈狀況執行本身的調度邏輯,進而將任務分配到各個節點上去執行。
咱們能夠看到,單體調度器擁有全局資源視圖和全局任務,能夠很容易地實現對任務的約束並實施全局性的調度策略。目前不少集羣管理系統採用了單體調度設計,好比Google Borg、Kubernetes等。Kubernetes的架構通過咱們以前的學習,相信你已經很熟悉了,下面咱們來介紹Borg的調度架構,因爲Kubernetes吸取了許多Borg的先進理念,說不定你會在Kubernetes的架構中看到許多Borg的影子。下面咱們來以Borg爲例,介紹一下它的單體調度實現。架構
Borg是谷歌內部的大規模集羣管理系統。有了以前的理論基礎,咱們直接上Borg的架構圖:
咱們看到,Borg主要由BorgMaster與Borglet構成。BorgMaster是整個集羣的大腦,Borglet表明集羣中的節點在這裏,咱們主要關注BorgMaster中的調度器Scheduler組件,它負責任務的調度,當用戶提交一個做業給 BorgMaster 後,BorgMaster 會把該做業保存起來,並將這個做業的全部任務加入等待隊列中。調度器異步地掃描等待隊列,將任務分配到知足做業約束、且有足夠資源的計算節點上。那麼,Borg調度器是如何快速找到知足任務資源需求的那個機器呢?這個算法主要分爲兩個階段:併發
首先看可行性檢查階段,這個很好理解。假如當前任務須要8G內存的資源,而某個機器的內存總數低於8G,那麼這臺機器則會被無情的過濾掉。框架
接下來就會進入到評分階段,既然如今的全部機器已經符合要求了,是否是咱們隨便找一臺機器把任務分了就完事了呢?其實不是。咱們能夠想一想,大概有以下兩種方案:異步
第一種方案被稱爲「最差匹配算法「,第二種方案被稱爲」最佳匹配算法「。咱們分析一下這兩種方案的優缺點:分佈式
在單體調度架構中,中央服務器的性能會限制調度的效率,這個很好理解,但爲何會限制支持的任務類型呢?
簡單地說,這是由於不一樣的服務具備不一樣的特徵,對調度框架和計算的要求都不同。好比說,你的業務最開始時只有批處理任務,後來發展到同時還包括流式計算任務。這兩種計算任務的資源與調度需求各不相同,因此咱們的調度器須要適配每一種任務,爲每個類型的任務設計不一樣的資源分配與調度策略,因此單體調度框架會隨着任務類型增長而變得愈來愈複雜,最終出現擴展瓶頸。
爲了解決以上單體調度的問題,一種方法就是另起一層,分擔中央服務器的任務,將任務調度與適配放到咱們剛纔說的具體的二層調度器中,一層調度器再也不去適配每一種任務的資源與調度需求。也就是說,一層調度器只負責資源管理和分配,二層調度器負責任務與資源的匹配。這就是咱們所的兩層調度架構。
總結一下,在兩層調度中,中央調度器從總體上收集節點資源信息,並進行資源的管理與分配,將資源分配到第二層調度器;再由第二層調度器負責將資源與具體的任務配對。因此,第二層調度能夠有多個調度器,以支持不一樣的任務類型:
看到這裏你們可能仍是不明白一層調度器這個資源分配,究竟是分配了什麼。咱們用一個例子來詳細講解一下:oop
Mesos也是一個大型分佈式集羣資源管理框架。既然是資源管理,因此Mesos只負責集羣底層資源的管理和分配,並不涉及任務調度與管理等功能。因此,Mesos若是要實現相似Borg那樣的資源與任務管理,還須要上層框架的配合。
Mesos自己實現的調度器爲第一層調度,負責資源管理,而後將第二層任務調度,交給框架完成。因此,Mesos是一個典型的兩層調度架構:
這裏咱們所說的二層調度的框架,是運行在Mesos上,是負責任務管理與調度的組件,好比 Hadoop、Spark等,每一個框架有他們本身的任務調度器,用於調度並完成不一樣的任務,好比批處理任務、實時分析任務等。框架主要由調度器(Scheduler)和執行器(Executor)組成,調度器能夠從 Master 節點獲取集羣節點的信息 ,執行器在Slave節點上執行任務。
在Mesos中,分配資源的過程叫作Resource Offer機制。Mesos Master主動將節點空閒資源,以相似發放Offer的方式發給每一個框架,若是框架須要則使用,不須要則還回。也就是說,經過 Resource Offer 機制,第一層調度器將資源主動分配給第二層調度器,而後第二層調度進行具體的任務匹配,從而實現了任務調度與資源管理的分離。
總結一下,Mesos Master經過資源分配算法決定給各個Framework提供多少資源,而Framework則決定接受哪些資源,以及哪些任務使用這些資源運行。這樣一來,一個兩層調度架構就實現了。
可是兩層調度的一個問題是,因爲第二層調度只能得到部分資源視圖,並無單體調度掌控全局的能力。所以沒法實現全局最優調度。爲了解決這個問題,共享狀態調度機制出現了。
爲了解決單體調度的擴展瓶頸問題,以及兩層調度只能得到部分資源視圖的問題,咱們想,那麼讓兩層調度器也可以看到全部節點的狀態不就能夠了,即咱們要一個地方來存儲全部節點的狀態就OK了。這,就是共享狀態調度。
共享狀態調度結合了單體調度掌控全局的特色,以及兩層調度職責分離的優點。經過將單體調度器分解爲多個調度器,且每一個調度器都有全局的資源狀態信息,從而實現最優的任務調度,提供了更好的可擴展性。其架構以下:
Omega是Google的第二代集羣管理系統,Omega 在設計時參考了 Borg 的設計,吸取了Borg 的優勢,並改進了其不足之處。
Omega中以Cell爲單位來管理集羣,它是一個集羣中的節點集合。好比集羣中有10個節點,那麼咱們能夠把其中的2個節點稱爲一個Cell。在Omega中,因爲須要共享每個Cell的資源狀態,那麼須要一個共享存儲空間,來共享每一個Cell的狀態。其架構圖以下:
咱們看到,爲了提升性能、而且能更方便的查到共享的集羣狀態數據,每一個Cell都會從中心的State Storage同步一份數據到每一個Cell內部。這樣一來,Omega 就有效地解決了兩層調度中 Framework 只擁有局部資源,沒法實現全局最優的問題。
那麼這幾種資源調度方案字哪一種場景下使用更好呢?
最後咱們把講過的三種調度方式作一個比較:
【分佈式系統遨遊】分佈式計算
歡迎對本系列文章感興趣的讀者訂閱咱們的公衆號,關注博主下次不迷路~