深度解析 | 基於DAG的分散式任務調度平台:Maat

深度解析 | 基於DAG的分散式任務調度平台:Maat

來自專欄我是程序員5 人贊了文章

背景

什麼是Maat?

Maat是一個基於開源項目Airflow的流程調度系統,它支持用戶自定義地組裝流程節點,流程可以在用戶指定的時間觸發(支持crontab格式),或由用戶手動觸發。

Maat的所有節點分散式地運行在Hippo上,由Drogo調度。用戶可以創建自己的調度節點和執行節點,達到資源隔離的目的。

用戶可以通過配置的方式安裝自己執行節點的運行環境,也可以配置執行節點的副本數。

下圖展示了一個任務的一次調度流程:

為什麼要做Maat?

我們在項目的開發過程中,經常遇到一些流程化/定時調度的需求,如上線發布流程、定時分析任務流程等。對於這些流程化的調度任務,我們嘗試過自己開發了一套流程調度系統,也嘗試過接入集團的工作流,但難免會遇到一些問題:

? 業務代碼和調度代碼耦合嚴重,修改流程基本需要入侵到代碼級別,業務代碼的發布影響調度。

? 對於這些調度任務,沒有一個統一管控的系統,難以管理和追溯。

? 多分支的複雜流程不能很好支持,上下文傳遞場景不能很好支持。

? 缺少可視化的UI,用戶使用不友好。

技術選型

定時任務&流程任務的調度是一個通用的需求,集團內的產品如D2、工作流,開源的產品如Airflow、Quartz等。

D2

D2是基於ODPS生態的一套流程調度系統,承載集團基於ODPS數據產出的調度任務。支持用戶自定義編寫腳本,支持定時任務觸發和手動觸發(補運行的方式),適合基於數據狀態的任務流程調度(如根據數據的產出執行任務流),由D2團隊專門維護,有較好的UI。

但它有一些不足:

? D2的DAG調度是一張大圖,每天需要運行的每個節點及拓撲關係是根據前一天的全局的拓撲關係計算得出的,所以新創建/修改的任務理論上只能第二天生效,如果想立即生效需要採用補運行的方式。業務上經常會有任務的變動(如任務配置或調度時間),或手動觸發一個調度的場景(如隨時發生的上線流程、全量流程),使用D2對業務不是很靈活,也不符合D2的使用場景。

? 不支持流程上下文的傳遞,業務上對上下文的傳遞比較強烈,經常有上個節點產出某個值,下個節點需要使用。

? 缺乏對搜索生態的支持。搜索技術部整個底層架構有自己的一套生態,如調度(Hippo,Drago)、報警(Kmon)。使用D2,不能充分享受搜索技術生態帶來的好處,對於之後的單元化部署也會帶來問題。

工作流

集團工作流是集團審批流程的一個通用調度引擎,很多產品的審批流程都是基於集團工作流的,同時它也可以作為一個簡易的任務調度流程使用,我們在Maat之前也使用集團工作流作為我們流程任務的調度引擎。它支持手動觸發,支持以HSF的方式調用外部系統,支持上下文傳遞。但它在配置上較為複雜,且支持外部系統的調用方式有限。

Quartz

Quartz是Java開源的任務調度框架。它支持分散式調度、支持任務持久化、支持定時任務,但不支持流程調度,且任務配置需要耦合在調度系統中,任務的熱載入需要做一些改造。

Airflow

開源項目Airflow是一套分散式的流程調度系統,它的優勢如下:

? 業務代碼和調度系統解耦,每個業務的流程代碼以獨立的Python腳本描述,裡面定義了流程化的節點來執行業務邏輯,支持任務的熱載入。

? 完全支持crontab定時任務格式,可以通過crontab格式指定任務何時進行。

? 支持複雜的分支條件,每個節點單獨設定觸發時機,如父節點全部成功時執行、任意父節點成功時執行。

? 有一套完整的UI,可視化展現所有任務的狀態及歷史信息。

? 外部依賴較少,搭建容易,僅依賴DB和rabbitmq。

? 有同學問到Luigi與Airflow的對比,個人感覺都是基於pipline的一個任務調度系統,功能也大同小異,Airflow屬於後來居上,功能更強,找到一篇同類產品的對比。

經過一段時間的調研,我們選用Airflow作為我們的原型開發一套分散式任務調度系統,它功能全面,基本滿足業務需求,在功能上擴展相對方便,外部依賴較少,和搜索生態對接相對容易。

原生Airflow的問題

Airflow可以解決流程調度中面臨的許多問題,但直接將原生的Airflow用於生產,仍面臨一些問題:

? 原生Airflow雖然支持分散式,但由於依賴本地狀態,不能直接部署在drogo上。

? 缺乏合適的監控手段,需要結合kmon完善監控和報警設施。

? 缺乏用戶友好的編輯手段,用戶需要了解Airflow的原理和細節。

? 大量任務運行時,調度的性能急劇下降。

? 分散式模式下,原生Airflow存在一些bug。

Maat架構

Maat架構:

業務層

任何流程式調度及定時觸發的需求均可以通過Maat創建應用,Maat提供了可視化編輯頁面及豐富的api,用戶可以方便地創建編輯流程模板,設置複雜的分支邏輯,Maat會在調度時按照運行時的狀態決定流程的流轉路徑。

目前接入Maat的應用場景包括Tisplus、Hawkeye、Kmon、容量平台、離線組件平台、Opensearch

管控層

由於原生Airflow的管控比較簡單,是基於描述任務流程dag的Python腳本調度,用戶要進行任務的創建、更新、運行需要深入學習Airflow原理才能上手,並且之後維護只能基於文件操作,非常不便。因此Maat在外層封裝一層管控系統Maat Console,降低運維及用戶學習的成本。

下圖是Maat管控系統Aflow的操作界面:

模板管理

在任務流程調度的場景中,常見的情況是:不同任務執行的流程基本一致,只有個別參數不同。因此Maat提出了基於模板管理的任務流程,用戶在模板管理中定義一個流程的運行模板,對於其中未確定的部分用變數表示。當生成具體任務時,由具體變數和模板渲染出具體的任務。當模板修改時,可以將模板生效到所有依賴該模板的任務。

模板管理預設了幾種任務節點,用戶可以自由選擇不同的任務節點組裝模板流程。

應用管理

管理所有具體的流程調度任務,包括任務使用的模板、變數的值、報警信息、任務觸發crontab等,用戶在通過模板創建應用後,後續可以通過應用管理繼續維護任務的運行。

隊列管理

由於Maat上運行的任務所屬應用各不相同,不同應用運行環境也不相同,另外不同應用也希望達到集群隔離的目的。為了實現這個功能Maat提供了隊列的管理,指定隊列的任務節點會被調度到相應隊列的機器上,相應隊列的機器也只會運行指定隊列的任務節點。

另外,隊列上也可以指定並發數,表示當前隊列上最多同時有多少個任務運行,確保機器上同時運行的任務不會太多導致負載過高,超出並發的任務會被掛起直到資源釋放。

核心模塊

Maat核心模塊完成了任務調度的整個流程。核心模塊的每個節點都獨立運行在機器上,啟動上互相不依賴,通過DB保存數據狀態,通過MQ或FaaS完成消息的分發。

Web Api Service

Web Api Service提供了豐富的與外部交互的Api,包括任務增刪改、歷史任務狀態、任務狀態修改、任務的觸發、任務的重試等介面。

另外原生Airflow提供的web展示功能也是由該角色完成。

Scheduler

scheduler是Maat關鍵角色,它決定了任務何時被調度運行,也決定一次任務運行中,哪些節點可以被執行。被判定執行的節點會被scheduler通過MQ或FaaS發送給worker執行。

隨著任務的增多,單一的scheduler負載過高導致調度周期增長,為了減輕scheduler的壓力,Maat將scheduler按照業務拆分。不同業務的任務有獨立的scheduler負責調度,發送任務到指定的Worker上。

Scheduler性能優化

原生Airflow的調度邏輯吞吐量較低,當任務量增多時,調度周期會很長,一些任務多的Scheduler延遲到達1分鐘左右。我們參考社區最新的實現,對原生調度邏輯進行優化,將原先阻塞的調度方式拆分為多個進程池,全非同步地完成可執行任務的生產->提交->輪詢操作。經過壓測原先調度周期為30s-40s的場景降低為5s左右。

Worker

worker為具體執行任務的角色,worker會接受scheduler發出的任務,在worker上執行節點中描述的具體任務。worker多副本部署,任務會在任意一個對等的worker上機器,當worker資源不足時,可以動態擴容。

由於不同隊列任務所需的基礎環境不同,如Python、Java、Hadoop、zk等,不同隊列的worker角色啟動參數有配置上的差異,不同隊列的worker啟動時會按照配置中描述的資源完成部署安裝。

worker上任務完成後會回寫db,scheduler察覺到當前任務狀態變化後會繼續任務的調度。

Distributers

任務分發層負責將scheduler需要調度的任務發送到指定的Worker上。目前Maat同時使用原生Celery+Rabbitmq的方式和搜索生態FaaS的方式實現任務分發。

Celery + RabbitMQ

原生Airflow使用Celery + RabbitMQ完成消息從Scheduler到Worker的分發。

Scheduler將需要運行的任務發送到MQ中,發送到MQ中包含任務對應的隊列信息。Worker從MQ獲取消息時,僅獲取相應隊列任務,拉取到對應Worker上執行。MQ在Maat中以rabbitmq實現,MQ和其他角色一樣,也是獨立部署的。

Celery + Rabbitmq的模型對消息隊列中的任務進行持久化,所有的任務狀態也進行持久化,內存Queue的性能滿足大部分場景的需求。但由於Maat基於二層調度Drogo部署,任何部署節點都要求無狀態的,而消息隊列MQ因為保存消息狀態顯然不滿足這個要求,所以我們選擇使用搜索生態的FaaS框架作為Celery + RabbitMQ的替代方案。

FaaS

FaaS:FaaS(Function as a Service)是基於搜索生態實現的ServerLess框架,Maat將其作為執行器。Maat的所有任務都抽象成function,任務執行時則調用相應的function,完成後返回任務狀態。目前已完成與FaaS的初步對接,期望未來能基於FaaS做更多優化。如:多樣化的任務執行方式,可以將輕量級的任務函數化,將重量級的任務服務化;任務資源動態調整,甚至某些任務可以執行時分配資源,完成後即釋放。

對於Maat來講,FaaS支持任務從生產者到消費者的分發,內置消息Queue,提供任務狀態介面,同時FaaS自身保證消息不對丟失,後續還具備根據消費者負載自動擴縮容的功能。

基礎組件

? DB:使用集團IDB,負責Maat信息的持久化,包括任務信息、任務運行歷史、任務運行狀態、節點運行歷史、節點運行狀態等。

? OSS:由於上drogo導致機器遷移的風險,所有日誌不能存放在本地,因此所有節點運行日誌存放在oss上,需要查看日誌上從oss上獲取。

? Kmon:完成監控集群運行狀態及任務失敗的報警功能。

? Drogo:完成Maat所有節點的docker容器化部署。

Maat平台的優勢

可視化編輯及通用的節點類型

Maat提供了一個管控平台Aflow,用戶可以方便地編輯流程節點,管理所有的模板和任務,詳細見上文的[管控層]。

除此之外,Maat還提供了豐富的通用節點類型。原生Airflow支持許多不同種類的節點類型,這些節點可以執行不同類型的任務。在與用戶的接觸中,Maat針對用戶的使用習慣與需求,對一些節點進行封裝,同時開發了幾種新的節點類型,可以滿足大部分用戶的需求。

? Bash節點:直接在worker上執行簡單的bash操作,由於bash通常需要依賴其他資源,實際使用較少,參照「帶資源的Bash節點」;

? Http節點:該節點支持http調用,調度時發送http請求觸發其他系統,同時該節點提供一個輪詢的http介面,觸發成功後輪詢其他系統是否成功,成功時才繼續運行;

? 帶資源的Bash節點:與普通Bash節點不同的是,該節點附帶一些資源(如jar包、bash腳本、Python腳本等),節點運行時會先將資源下載到本地,然後執行bash腳本;

? 分支節點:該節點根據之前節點的運行結果或初始傳入的參數決定分之後的節點走哪個分支。

Drogo化部署

Maat服務有多種角色,每種角色都需要不同的運行環境,為了維護這些運行環境,對運維同學來說絕對是個噩夢,這種情況下上hippo成為Maat運維最好的選擇。drogo作為基於二層調度服務的管控平台,為Maat各個節點部署在hippo上成為可能。具體來說,Drogo化的優勢如下:

? 低成本增加新節點。上Drogo前,有新增節點的需求時,每次都需要準備運行資源,重新寫部署腳本,而每個節點的腳本都要運維同學自己維護。上Drogo後,所有這些部署信息保存在Drogo平台上,有新的的節點也只需要將之前類似的部署信息複製,稍加修改即可。

? 擴容簡單。上Drogo前,某類任務水位太高,為這類任務擴容,每次都需要準備機器、準備環境、調試運行參數,可能需要半天到一天的時間。上Drogo後,調整副本數,Drogo會自動擴容。

? 有效防止機器遷移帶來的服務中斷。上Drogo前,機器出現問題後,只能另找機器擴容,對於某些只能單點運行的節點,只能燒香祈禱機器不掛了。上Drogo後,機器遷移後,會Drogo會自動分配一台機器將服務拉起,對於可中斷的服務,單節點部署也不用擔心機器掛了導致服務消失了。

下圖展示了目前Drogo上部署的Maat各個角色:

由於原生Airflow的一些節點是有狀態的,需要依賴本地一些文件,機器遷移會導致這些節點的狀態丟失,我們對Maat做了一些修改,保證機器遷移不會丟失運行狀態:

? 之前的調度依賴本地Python dag文件,機器遷移導致本地文件丟失。我們做了修改,所有dag保存在db,依賴db中保存的信息調度,保證機器遷移後,dag信息也不會丟失。

? 由於基於本地文件,web service和scheduler讀寫的都是同一份dag文件,導致原生Airflow的scheduler和web service角色必須綁定運行。以db中信息調度後,web service和scheduler可以單獨部署。

? 由於原來日誌文件保存在本地,機器遷移會導致日誌文件丟失。我們改造後,將日誌文件保存在oss遠端,每次讀取日誌從遠端讀取。

分集群管理

由於不同任務隔離的需求,Maat基於Airflow原生的隊列管理擴展不同任務的集群管理功能,不同類型的任務可以創建自己的scheduler和worker,創建應用時可以使用指定的scheduler調度或運行在指定worker上(如果不指定由默認scheduler和worker調度)。

集群的配置參數包括以下信息:

? worker部署配置:該worker依賴的資源,drogo啟動時會將任務運行需要的資源部署到worker機器上,機器遷移時也會使用這份部署配置重新分配資源。

? worker個數:控制worker角色的個數。

? 集群並發數:控制集群中正在運行的並發數,防止任務運行過多導致下游系統壓力過大。

? scheduler:目前每個集群只有一個scheduler,後續會改造成支持多個scheduler調度節點。

監控&報警

平台監控報警

為了掌握平台的運行狀況,Maat在各個節點的關鍵步驟向kmon彙報metric信息,metric異常狀態下會發送報警給開發同學。也可以根據這些metric信息判斷當前集群的負載狀況,對任務負載較高的節點進行優化。

任務報警

對於具體任務,Maat支持在每個任務節點運行異常的情況下發送報警,如節點運行異常、任務未按時運行、任務運行超時等。用戶可以在管控平台設置報警條件及報警接收人。

平台現狀

Maat是一個通用基於Dag的任務調度系統,服務於集團內部和雲上的許多場景:

? 搜索中台Tisplus:調度Tisplus的上線流程及其他需要定時觸發的任務;

? Hawkeye:定時調度Hawkeye的分析任務;

? 搜索監控平台Kmon:支持kmon的監控託管服務及報警處理流程;

? 搜索容量預估平台Torch:支持容量預估流程的管控;

? 搜索離線平台Bahamut:支持離線組件平台發布流程、全量流程;

? Opensearch:一些演算法場景的離線任務;

? Tpp:推薦場景的流程調度任務。

Maat線上集群任務執行現狀(2018.8.13數據):

? 日均調度任務:3000+個

? 日均運行任務:24K+次

隨著更多應用場景的接入,平台能力將會接受進一步的考驗。

未來展望

隨著業務的接入和數據規模的增大,Maat平台也需要進一步提升用戶體驗,提昇平台穩定性。

? 與Aflow進一步結合,在管控平台上一站式完成集群的創建、配置、部署。

? 提供更加豐富的報警選項,進一步加強錯誤的反饋機制。

? 隨著任務數量的增多,一些調度上的缺陷逐漸體現出來,對於這些缺陷做進一步優化。

? 和FaaS深度合作,為各類任務創建單獨的FaaS服務,降低資源利用率。

本文作者:斯蘭

原文鏈接

更多技術乾貨敬請關注云棲社區知乎機構號:阿里云云棲社區 - 知乎

本文來自雲棲社區合作夥伴「阿里技術」,如需轉載請聯繫原作者。


推薦閱讀:

基於IPFS的分散式數據共享系統的研究
PacifiaA讀書筆記
分散式系統的那些事兒(四) - MQ時代的通信
基於靈活高速的存儲系統Alluxio 訓練深度學習模型

TAG:分散式計算 | 分散式系統 | 工作流 |