在上述方案中,A的每個(gè)任務(wù)消耗總cpu的1/9和總內(nèi)存的2/9,所以A的dominant resource是內(nèi)存;B的每個(gè)任務(wù)消耗總cpu的1/3和總內(nèi)存的1/18,所以B的dominant resource為CPU。DRF會(huì)均衡用戶的dominant shares,執(zhí)行3個(gè)用戶A的任務(wù),執(zhí)行2個(gè)用戶B的任務(wù)。三個(gè)用戶A的任務(wù)總共消耗了{(lán)3CPU,12GB},兩個(gè)用戶B的任務(wù)總共消耗了{(lán)6CPU,2GB};在這個(gè)分配中,每一個(gè)用戶的dominant share是相等的,用戶A獲得了2/3的RAM,而用戶B獲得了2/3的CPU。
以上的這個(gè)分配可以用如下方式計(jì)算出來:x和y分別是用戶A和用戶B的分配任務(wù)的數(shù)目,那么用戶A消耗了{(lán)xCPU,4xGB},用戶B消耗了{(lán)3yCPU,yGB},在圖三中用戶A和用戶B消耗了同等dominant resource;用戶A的dominant share為4x/18,用戶B的dominant share為3y/9。所以DRF分配可以通過求解以下的優(yōu)化問題來得到:
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}。
HierarchicalDRF核心算法實(shí)現(xiàn)在Src/main/allocator/mesos/hierarchical.cpp中HierarchicalAllocatorProcess::allocate函數(shù)中。
概況來說調(diào)用了三個(gè)Sorter(quotaRoleSorter, roleSorter, frameworkSorter),對(duì)所有的Framework進(jìn)行排序,哪個(gè)先得到資源,哪個(gè)后得到資源。
總的來說分兩大步:先保證有quota的role,調(diào)用quotaRoleSorter,然后其他的資源沒有quota的再分,調(diào)用roleSorter。
對(duì)于每一個(gè)大步分兩個(gè)層次排序:一層是按照role排序,第二層是相同的role的不同F(xiàn)ramework排序,調(diào)用frameworkSorter。
每一層的排序都是按照計(jì)算的share進(jìn)行排序來先給誰(shuí),再給誰(shuí)。
這里有幾個(gè)概念容易混淆:Quota, Reservation, Role, Weight
每個(gè)Framework可以有Role,既用于權(quán)限,也用于資源分配
可以給某個(gè)role在offerResources的時(shí)候回復(fù)Offer::Operation::RESERVE,來預(yù)訂某臺(tái)slave上面的資源。Reservation是很具體的,具體到哪臺(tái)機(jī)器的多少資源屬于哪個(gè)Role
Quota是每個(gè)Role的最小保證量,但是不具體到某個(gè)節(jié)點(diǎn),而是在整個(gè)集群中保證有這么多就行了。
Reserved資源也算在Quota里面。
不同的Role之間可以有Weight
在allocator算法結(jié)束之后,便調(diào)用Master::Offer,最終調(diào)用Framework的Scheduler的resourceOffers,讓Framework進(jìn)行二次調(diào)度。同上面的邏輯就串聯(lián)起來。
第三、寫一個(gè)Hook
你可以寫hook模塊,講代碼插在很多關(guān)鍵的步驟,從而改寫整個(gè)Executor或者Docker或者Task的啟動(dòng)的整個(gè)過程。
可以干預(yù)的hook的地方定義在mesos/hook.hpp中。
Class hook定義如下:

其中比較常用的是slavePrelaunchDockerHook,可以在Docker啟動(dòng)之前做一些事情,比如準(zhǔn)備工作。
還有slaveRemoveExecutorHook,這個(gè)可以在executor結(jié)束的時(shí)候,做一些事情,比如清理工作。
第四、創(chuàng)建Isolator
當(dāng)你有一種新的資源需要管理,并且每個(gè)Task需要針對(duì)這個(gè)資源進(jìn)行隔離的時(shí)候,寫一個(gè)Isolator就是有必要的了。
例如默認(rèn)的容器并不能動(dòng)態(tài)指定并限制任務(wù)硬盤使用的大小,所以mesos-containerizer就有了"disk/du"來定時(shí)查看任務(wù)使用的硬盤大小,當(dāng)超出限制的時(shí)候采取操作。
Src/slave/containerizer/mesos/containerizer.cpp里面列出了當(dāng)前支持的isolator,你也可以實(shí)現(xiàn)自己的isolator,并且通過modules參數(shù)load進(jìn)去。
Isolator定義了以下函數(shù)

在運(yùn)行一個(gè)容器的最后,會(huì)調(diào)用每一個(gè)isolator的isolate函數(shù),通過這個(gè)函數(shù),可以對(duì)資源進(jìn)行一定的限制,例如寫入cgroup文件等,但是對(duì)于硬盤使用量,其實(shí)沒有cgroup可以設(shè)置,需要過一段時(shí)間du一些,這就需要實(shí)現(xiàn)watch函數(shù),過一段時(shí)間查看一下硬盤使用量,超過后做一定的操作。
第五、寫一個(gè)Executor
如果運(yùn)行一個(gè)普通的容器,或者命令行,則不需要實(shí)現(xiàn)Executor,僅僅Mesos默認(rèn)的Executor就能夠?qū)崿F(xiàn)這個(gè)功能。如果你需要在Executor里面做很多自己定制化的工作,則需要自己寫Executor。
寫一個(gè)Executor需要實(shí)現(xiàn)一些接口,最重要的就是launchTask接口,然后MesosExecutorDriver將這個(gè)Executor運(yùn)行起來。