一提mesos,不少人知道雙層調度,可是大多數理解都在表面,否則試一下下面五個問題。算法
問題一:若是有兩個framework,一萬個節點,按說應該平均分配給兩個framework,怎麼個分法?一人一臺這樣分,仍是前五千給一人,後五千給第二我的,仍是隨機分,隨機分怎麼個分法?微信
問題二:在沒有reserved狀況下,每一個節點是隻能得給一個framework,仍是能夠分給多個framework?數據結構
問題三:若是兩個framework的權重比例爲1比2,是如何保證資源分配是這個比例?dom
問題四:若是兩個framework的權重比例爲1比2,當第二個用完了三分之二,在第一個沒有任務運行的時候,第二個能多用一些麼?如何平衡別人不用多用,別人要用保持比例呢?函數
問題五:將資源提供給多個framework的時候,是一個節點的資源給第一個framework,第一個framework說我不用,而後再給第二個framework麼?優化
好了,接下來咱們來看Mesos雙層調度的基本原理。spa
1、入門級理解Mesos雙層調度orm
Mesos的調度過程如圖所示:blog
Mesos有Framework, Master, Agent, Executor, Task幾部分組成。這裏面有兩層的Scheduler,一層在Master裏面,allocator會將資源公平的分給每個Framework,二層在Framework裏面,Framework的scheduler將資源按規則分配給Task。排序
2、進階級理解Mesos雙層調度
Mesos採用了DRF(主導資源公平算法 Dominant Resource Fairness),Framework擁有的所有資源類型份額中佔最高百分比的就是Framework的主導份額。DRF算法會使用全部已註冊的Framework來計算主導份額,以確保每一個Framework能接收到其主導資源的公平份額。
舉個例子
考慮一個9CPU,18GBRAM的系統,擁有兩個用戶,其中用戶A運行的任務的需求向量爲{1CPU, 4GB},用戶B運行的任務的需求向量爲{3CPU,1GB},用戶能夠執行儘可能多的任務來使用系統的資源。
在上述方案中,A的每一個任務消耗總cpu的1/9和總內存的2/9,因此A的dominant resource是內存;B的每一個任務消耗總cpu的1/3和總內存的1/18,因此B的dominant resource爲CPU。DRF會均衡用戶的dominant shares,執行3個用戶A的任務,執行2個用戶B的任務。三個用戶A的任務總共消耗了{3CPU,12GB},兩個用戶B的任務總共消耗了{6CPU,2GB};在這個分配中,每個用戶的dominant share是相等的,用戶A得到了2/3的RAM,而用戶B得到了2/3的CPU。
以上的這個分配能夠用以下方式計算出來:x和y分別是用戶A和用戶B的分配任務的數目,那麼用戶A消耗了{xCPU,4xGB},用戶B消耗了{3yCPU,yGB},在圖三中用戶A和用戶B消耗了同等dominant resource;用戶A的dominant share爲4x/18,用戶B的dominant share爲3y/9。因此DRF分配能夠經過求解如下的優化問題來獲得:
max(x,y) #(Maximize allocations)
subject to
x + 3y <= 9 #(CPU constraint)
4x + y <= 18 #(Memory Constraint)
2x/9 = y/3 #(Equalize dominant shares)
最後解出x=3以及y=2,於是用戶A得到{3CPU,12GB},B獲得{6CPU, 2GB}。
3、代碼級理解Mesos雙層調度
首先理解幾個概念容易混淆:Quota, Reservation, Role, Weight
每一個Framework能夠有Role,既用於權限,也用於資源分配
能夠給某個role在offerResources的時候回覆Offer::Operation::RESERVE,來預訂某臺slave上面的資源。Reservation是很具體的,具體到哪臺機器的多少資源屬於哪一個Role
Quota是每一個Role的最小保證量,可是不具體到某個節點,而是在整個集羣中保證有這麼多就好了。
Reserved資源也算在Quota裏面。
不一樣的Role之間能夠有Weight
Mesos的代碼實現中,不是用原生的DRF,而是使用HierarchicalDR,也即分層的DRF.
調用了三個排序器Sorter(quotaRoleSorter, roleSorter, frameworkSorter),對全部的Framework進行排序,哪一個先獲得資源,哪一個後獲得資源。
總的來講分兩大步:先保證有quota的role,調用quotaRoleSorter,而後其餘的資源沒有quota的再分,調用roleSorter。
對於每個大步分兩個層次排序:一層是按照role排序,第二層是相同的role的不一樣Framework排序,調用frameworkSorter。
每一層的排序都是按照計算的share進行排序來先給誰,再給誰。Share的計算就是按照DRF算法。
接下來咱們具體分析一下這個資源分配的過程。
1. 生成一個數據結構offerable,用於保存資源分配的結果
hashmap<FrameworkID, hashmap<SlaveID, Resources>> offerable;
這是一個MAP,對於每個Framework,都會有一個資源的MAP,保存的是每一個slave上都有哪些資源。
2. 對於全部的slave打亂默認排序,從而使得資源分配相對均勻
std::random_shuffle(slaveIds.begin(), slaveIds.end());
3. 進行第一次三層循環,對於有quota的Framework進行排序
foreach (const SlaveID& slaveId, slaveIds) {
foreach (const string& role, quotaRoleSorter->sort()) {
foreach (const string& frameworkId_, frameworkSorters[role]->sort()) {
對於每個slave,首先對role進行排序,對於每個role,對於Framework進行排序,排序靠前的Framework優先得到這個slave。
排序的算法在DRFSorter裏面實現,裏面有一個函數calculateShare,裏面的關鍵點在於進行了一個循環,對於每一種資源都計算以下的share值:
share = std::max(share, allocation / _total);
allocation除以total即一種資源佔用的百分比,這裏之因此求max,就是找資源佔用百分比最高的資源,也即主導資源。
可是這個share不是直接進行排序,而是share / weights[name]除以權重進行排序。若是權重越大,這個值越小,這個role會排在前面,分配更多的資源。
排序結束後,對於每個Framework,將當前slave的資源分配給它。
Resources available = slaves[slaveId].total - slaves[slaveId].allocated;
首先查看這個slave的可用資源,也即總資源減去已經分配的資源。
Resources resources = (available.unreserved() + available.reserved(role)).nonRevocable();
每一個slave上沒有預留的資源和已經預留給這個Framework的資源都會給這個Framework,固然若是上面有預留給其餘Framework的資源是不會給當前的Framework的。
offerable[frameworkId][slaveId] += resources;
slaves[slaveId].allocated += resources;
分配的資源會保存在數據結構offerable中。
4. 進行第二次三層循環,對於沒有quota的Framework進行排序
foreach (const SlaveID& slaveId, slaveIds) {
foreach (const string& role, roleSorter->sort()) {
foreach (const string& frameworkId_,frameworkSorters[role]->sort()) {
5. 所有分配結束後,將資源真正提供給各個Framework
foreachkey (const FrameworkID& frameworkId, offerable) {
offerCallback(frameworkId, offerable[frameworkId]);
}
這裏的offerCallback是調用Master::Offer,最終調用Framework的Scheduler的resourceOffers,讓Framework進行二次調度。
最後,讓咱們來解答一下這些問題:
問題一:若是有兩個framework,一萬個節點,按說應該平均分配給兩個framework,怎麼個分法?一人一臺這樣分,仍是前五千給一人,後五千給第二我的,仍是隨機分,隨機分怎麼個分法?
答:是隨機分,怎麼分呢?是將節點隨機排序,可是排好序以後,就再也不隨機分了,而是開始排序,好比隨機後的節點隊列中的第一個節點分給了第一個framework,等下次循環再排序的時候,第二個framework因爲沒有拿到資源,排在了第一個framework的前面,因而第二個節點就分配給了第二個framework,而後for循環到第三個節點的時候(這是外層循環),內層循環對framework排序的時候,第一個framework又排在了第二個前面,因而第三個節點分給了第一個framework。就這樣你一個,我一個,實現了平均分配。
問題二:在沒有reserved狀況下,每一個節點是隻能得給一個framework,仍是能夠分給多個framework?
答:是的,在沒有reserved的狀況下,一個節點是隻給一個framework,若是有reserved的狀況下,reserved的那部分會給reserve它的那個framework,其餘的部分,仍是隻能給一個framework,不必定是哪個,看誰排在前面。
問題三:若是兩個framework的權重比例爲1比2,是如何保證資源分配是這個比例?
答:也是經過排序來的,對節點的for循環是外層循環,對framework的排序和循環是內層循環,第一次排序的時候,權重爲2的framework排在前面,因而第一個節點是它的,第二次排序的時候,仍是權重爲2的framework排在前面,因而第二個節點也是它的,第三次排序的時候,權重爲1的framework因爲歷來沒拿到過資源,排在了前面,因而第三個節點是它的。就這樣你兩個,我一個,你兩個,我一個,實現了資源按權重分配。
問題四:若是兩個framework的權重比例爲1比2,當第二個用完了三分之二,在第一個沒有任務運行的時候,第二個能多用一些麼?如何平衡別人不用多用,別人要用保持比例呢?
答:能的。若是權重爲2的framework用完了三分之二,則每次排序,它都會排在權重爲1的可是沒有獲得資源的framework後面,按說它永遠得不到資源。可是算法中會有一個filter機制,當一個節點分給某一個framework以後,若是這個framework不用,退回來,則下次再遇到這個framework的時候,先filter掉,這樣另外一個framework就有機會獲得這個節點了。下次又不會filter掉了。
問題五:將資源提供給多個framework的時候,是一個節點的資源給第一個framework,第一個framework說我不用,而後再給第二個framework麼?
答:不是的。統一運行一遍分配算法,把資源都所有分配好,才統一發送給framework,若是須要再次分配,是下次統一計算的時候了。
歡迎關注微信公衆號