背景
順着昨天spark standalone實現那篇文章繼續扯淡,看看Mesos Scheduler的兩種實現的異同。
對我來說,回過頭再仔細看Spark在這一層的實現,思路又清晰了許多。
Mesos粗粒度
CoarseMesosSchedulerBackend,是mesos的粗粒度scheduler backend實現。
簡單說一下mesos的Scheduler,提供的回調函數,及spark實現的邏輯:
Mesos Scheduler接口 | 觸發場景 | spark實現邏輯 |
void registered( SchedulerDriver driver, FrameworkID frameworkId, MasterInfo masterInfo); | 當Scheduler成向mesos master註冊之後回調, 會返回唯一的framework id | 得到framework的id,作爲appId |
void reregistered( SchedulerDriver driver, MasterInfo masterInfo) | 是mesos換了個新選舉出來的master的時候觸發, 前提是該scheduler之前已經註冊過了 | 沒有實現。 |
void resourceOffers( SchedulerDriver driver, List<Offer> offers) | mesos提供了一批可用的資源,讓scheduler可以使用或拒絕這些資源。 每個Offer是以slave爲單位的,即以slave爲單位的資源列表。 | 得到mesos的Offers列表,只要已經啓動的executor還不足夠, 那麼從資源列表裏繼續獲取資源,啓動CoarseGrainedExecutorBackend。 |
void offerRescinded( SchedulerDriver driver, OfferID offerId) | 當請求的offer不可用時回調(可能是slave lost了之類的原因導致的), 如果在這上面繼續起task的話會報Task Lost的狀態。 | 沒有實現。spark在task scheduler層面對lost的task有自己的處理,。 |
void statusUpdate( SchedulerDriver driver, TaskStatus status) | task狀態更新回調,可能是finish了,可能是lost了,可能是fail了等等 | 得到finished、failed、lost等task狀態,更新內存裏維護的task狀態, 並觸發新一輪的reviveOffers,即通過task scheduler繼續把resource分配給需要的task並執行它們。 |
void frameworkMessage( SchedulerDriver driver, ExecutorID executorId, SlaveID slaveId, byte[] data) | 用於接收executor主動發的消息 | 沒有實現。mesos雖然在內部提供了這種msg接口,貌似不是很穩定。 使用方可以使用自己的RPC來做executor與scheduler的通信,如果真的需要的話。 |
void disconnected( SchedulerDriver driver) | 當scheduler與master斷開的時候觸發, 原因可能是master掛了,或者master換了等等。 | 沒有實現。spark前面就沒有實現master新選舉的接口。 |
void slaveLost( SchedulerDriver driver, SlaveID slaveId) | 通知某個slave lost了,以便framework進行任務的rescheduler或其他邏輯 | spark把slave lost和executor lost一起處理了。 處理邏輯就是執行RemoveExecutor操作,最終調用TaskScheduler的executorLost方法,把executor的狀態移除, 並且會繼續向上調用DAGScheduler的handleExecutorLost方法。 因executor lost可能會影響到shuffle數據,這部分還需要BlockManager感知。 |
void executorLost( SchedulerDriver driver, ExecutorID executorId, SlaveID slaveId, int status) | 通知某個slave上的executor掛了。 | 同上 |
void error( SchedulerDriver driver, String message) | scheduler或scheduler driver發送錯誤觸發 | 沒有實現 |
另一方面,要說明一下mesos的SchedulerDriver。
它相當於是Scheduler與mesos通信的一個連接人,一方面是管理Scheduler的生命週期,二方面是與mesos交互,讓它啓停task。
在初始化SchedulerDriver的時候,向裏面傳入spark自己實現的Scheduler就可以了,即CoarseMesosSchedulerBackend或MesosSchedulerBackend。在每個mesos的Scheduler接口的回調方法裏,都會傳回SchedulerDriver,以對應可以進行scheduler的啓停和task的啓停管理。
CoarseMesosSchedulerBackend內部主要維護的信息爲:slave與executor的對應關係,executor與task的對應關係,task與slave的對應關係。
Mesos細粒度
翻譯下注釋:
細粒度模式下,允許多個app共享nodes,包括空間,即不同app的tasks可以跑同幾個core,和時間,即一個core可以切換ownership。
這塊共享的控制,在mesos端,所以spark在實現的時候,其實差別和難度都不大。
MesosSchedulerBackend的實現:
在resourceOffers邏輯裏,獲得mesos提供的slave資源後,直接在裏面調用scheduler的resourceOffers,即TaskSchedulerImpl的分配task的邏輯。也就是說,會按優先級,從active task sets(來自多個app)裏選擇並直接launch task。而粗粒度裏的做法,是先啓動executorbackend,把資源準備好,進程先拉起,供app去launch task。
其他回調接口的邏輯是大同小異的。
還有一點不同之處,粗粒度模式下executor的實現使用的是與standalone模式相同的CoarseGrainedExecutorBackend。在細粒度模式下,executor的實現是MesosExecutorBackend,實現了spark的ExecutorBackend和mesos的MesosExecutor。實際上,在類裏面,還是使用的spark的executor,在對應的回調裏執行start/kill task這樣的操作。另外,mesos的ExecutorDriver用於負責與mesos通信,比如傳遞一些狀態更新的消息,或有特殊的msg要發送。executor這塊的差別無關緊要。
在我看來,executor這塊最終一定是落到了spark的executor上,裏面有一個線程池,可以跑spark的ShuffleMapTask或ResultTask。而mesos粗、細粒度的Scheduler實現,最大區別在於resourceOffers的邏輯,是怎麼處理分配的進程資源:粗粒度是預先拉起執行進程,而細粒度是直接通過TaskScheduler來擺放執行線程了。
粗細粒度分別適合跑什麼樣的任務,可以具體見 官方文檔這一節
全文完 :)