一、調度系統簡介
Buffalo調度是一款京東自主研發的分布式DAG作業調度系統。為京東的數據開發工程師、算法工程師、數據分析師等用戶提供了離線作業的編排&調試、監控運維、DAG調度等系統能力,致力于打造行業領先的穩定高效、產品簡潔高體驗、任務監控全面、資源容器化、系統能力開放化的ETL調度系統。
在京東調度系統核心面臨的挑戰有以下幾個:
1.業務復雜帶來的依賴關系復雜:復雜的數據鏈路,使得部分任務有數百、甚至上千個上下游,層級多達數十層。跨天依賴、數據回刷、月度匯總等業務場景,需任務間依賴存在大小周期依賴、跨天依賴等復雜場景,任務依賴關系數據構成一個龐大且復雜的有向無環圖。
2.業務體量大且穩定性&性能要求高:目前平臺有數十萬任務,百萬+依賴關系,日均百萬+調度頻次,不僅關系復雜、執行量大,且系統的任何細微異常,都可能導致數據鏈路異常,核心數據受損,這對調度系統的穩定性和性能帶來了不小挑戰。
3.數據加工場景復雜需支撐豐富調度能力:支持集團多個BG業務,業務場景多樣,涉及數據采集、數據計算、數據推送、數據轉換等多種任務類型、多種執行方式、多種觸發規則,以及控制節點、任務間的數據傳遞、數據補錄場景等,對系統功能的豐富度和靈活度提出新要求。
二、核心技術方案
為支撐靈活的業務加工和工作流編排場景,快速的業務發展帶來的任務量增長,以及保障整個系統的穩定性,我們從易用性、穩定性、以及高性能等方面做了很多的思考和優化,下面我將著重從這三個方面詳細介紹。
1. 實體和編排調度模型
a) 雙層實體模型
采用主流的雙層實體模型,雙層實體模型中,包含兩個核心概念:
?Action(環節):環節是最小粒度的執行單位,攜帶執行相關的信息,如腳本、參數、環境等。
?Task(任務):任務是由一個或多個環節+觸發規則構成的DAG,Task和Task之間也可以相互依賴,在外層構成一個DAG,實現雙層調度。
相比單層實體模型,編排能力更強,有更好的靈活性,同時對于單個業務的整合打包和管理也更友好。
b) 基于實例的調度
任務定義是任務配置的載體,無狀態,不可執行,任務當到達運行周期時,會產生相應周期的任務實例(產生實例的過程叫“實例化”),實例化時會根據任務的配置信息,包括:環節、上游依賴、數據依賴、運行周期等,生成當前周期實例,可理解為任務的一個快照,任務實例是真正可執行、并具有狀態的對象。
基于實例的調度模式,其優點在于:
?周期穩定:任務的每個周期都會有實例,不會出現周期缺失的情況,且每個周期的實例可獨立操作
?依賴明確:任務某個周期的實例,其對上游任務實例的依賴,或者數據依賴是明確的、可預期的,同時對某個周期的數據可從整個鏈路上快速追溯,并在產生問題是可從鏈路層面快速修復。
c) 分類分級調度能力
平臺中的任務不通業務,重要性存在一定差異,為提升核心任務的保障能力,平臺提供任務分類分級管理,和基于分級的調度能力,在客戶端資源較為緊張時,會優先保障重要業務。同時任務等級信息會透傳到底層集群,在底層計算集群層面也增加相應基于分類和等級的保障策略,保障核心業務的穩定性。
2. 高可用架構
buffalo整體有分三層,每一層都具備高可用架構,使得整體具備高可用和容災能力
?a) Manager管理層:
?主要提供產品化管理能力,包括任務的創建、任務管理、任務運維等,管理端無狀態,可橫向擴展,負載對外提供服務
?b) 高可用Scheduler:
?也叫NameNode是Buffalo核心調度引擎,負責任務實例的周期生成,以及基于DAG的雙層任務實例的調度、客戶端資源的調度(物理資源、彈性資源)、任務狀態的處理等。
?整體采用多活+主備高可用架構,多個scheduler會通過數據分片負載處理任務,同時對于任務狀態消息進行冪等處理,其中資源調度模塊采用主備模式,以便支撐靈活和高效的資源調度能力。當一個節點故障時,其他節點會監測到節點下線,并自動觸發接管邏輯,將異常節點任務接管處理,保障故障節點上的任務執行不受影響。
?c) 容錯執行層:
?執行層的核心職責是負責任務啟動執行,并監聽任務執行結果、采集任務日志、上報任務狀態,執行層支持物理機和基于k8s的容器化資源兩種模式。
?物理機:部署worker(也稱TaskNode)長進程,任務以獨立進程方式運行,多個worker構成節點組對(虛擬節點)外服務,避免單點故障問題。同時worker本身支持消息重傳、cgroup資源隔離等高可用特性。
?k8s彈性資源:與原生k8s對接,任務以短周期pod方式執行,任務結束時pod銷毀,天然具備高可用特性,同時具備更精細化的資源管理、差異化執行環境的動態構建能力。
3. 高性能
前面提到調度系統中隨著任務量的增長,業務復雜度的提升,需要調度執行的DAG實例梳理,以及DAG的復雜度都會不斷提升,buffalo主要從以下幾個方面來做到高容量、低延遲的編排和調度。
1) 水平擴展
如上高可用架構部分介紹,調度引擎采用多活架構,可水平擴展,不同服務之間通過數據哈希分片,將任務負載分布到多臺服務進行調度,同時各服務通過執行批次和狀態進行冪等處理,保障任務執行的唯一性。
2) 事件驅動
a. 定時輪詢(如左圖)
傳統的任務執行方式大多采用定時輪詢的方式,這種方式需要定時查詢所有待執行的任務實例,然后逐一校驗任務實例的依賴條件是否滿足(如任務依賴、數據依賴、并發限制等),這種方式在面臨大數據量任務時,有幾個核心問題:
?遍歷耗時:系統中可能有非常多的任務待執行(有些滿足條件、有些不滿足條件),這樣每次獲取的任務列表會非常長(可能數十萬或百萬),這樣遍歷一遍非常耗時
?大量無用計算:在這些獲取的任務列表中,每個任務都需要進行多種條件校驗,且只有少數任務是滿足執行條件,絕大部分的校驗是無用校驗
b. 基于事件驅動(如右圖)
相比定時輪詢,事件驅動不會采用定時拉取、全量校驗的方式,而是在任務所依賴條件的狀態發生變更時,才會基于事件做出相應的條件計算和校驗動作,這樣可以有效避免定時輪詢面臨的兩個核心問題。同時針對不同的事件類型,可以分別進行異步并行處理,有效提升整體的處理性能。
3) 內存調度
前面提到Buffalo具備在物理機集群和k8s集群上啟動任務執行的能力,所以需要具備這兩種資源的管理和資源調度能力,資源調度的性能也是影響任務分發時效的關鍵部分。
調度引擎namenode采用的是多活的高可用架構,如果資源調度部分也采用該架構(如左圖),那么涉及到同一資源的并發訪問和修改的問題,進而引入分布式鎖和外部存儲,這樣整體的性能很難達到理想的目標。
因此,我們在namenode多活架構的基礎上,將資源調度部分做了一個主備架構的處理(如右圖),會從多個namenode里選擇一個作為主資源調度器,其他作為熱備,所有namenode的任務資源請求都由主節點進行處理,這樣主節點在內存中保存了所有的資源信息,資源調度過程在內存中就可進行,避免了分布式鎖和對外部存儲的依賴,性能有大幅提升。
4) 冷熱數據分離
當系統中任務量較大,任務執行產生的實例數據會快速增長,當前buffalo每日的實例數據增量接近百萬,隨著任務量的增長還會持續增長,如果沒有適當的方案來處理,數據庫很難支撐如此快速的數據增長。
調度系統中的任務有個明顯特征 -定時,就是任務會定時執行,執行完成后的實例,除人為干預外其狀態不會再自動發生變更,這部分數據一般只會做查詢,所以這部分數據可以做獨立存儲。我們將狀態還會發生變更或頻繁操作的數據稱作熱數據,將這些已經執行結束且基本只有查詢需求的數據稱作冷數據,并將冷數據單獨存儲。
當冷熱數據分離后,有三個核心問題需要解決:
1)數據結轉
任務實例執行完成,處于結束狀態的實例都可以被結轉,目前采用定時結轉的策略。為避免冷數據單表數據量過大,結轉規則可以按照季度、月或則更小周期進行拆分存儲。
2) 數據定位
當數據結轉到冷數據表后,這些實例的狀態不會發生變更,單可能還會被未執行的實例所依賴,用戶也可能會對這些實例做檢索操作,所以這些實例需要能從冷數據表中快速被定位。
?索引表:數據結轉到冷數據表時,會根據冷數據表的分區粒度,在索引表記錄各冷分區表中的數據范圍,如計劃運行時間在2023-01-01 至 2023-03-31的數據存儲在2023Q1分區表,這樣在定位時可以圈定數據范圍,避免全量掃描。
?數據定位:因實例數據是有周期性的,有非常強的時間特性,所以可以結合任務實例的計劃運行時間,和索引表的數據范圍,快速定位任務某個范圍的實例所在的分區。
3)冷數據操作
冷數據被操作的幾率比較低,但也存在操作的可能性,比如歷史實例的重跑、強制成功等操作。為了保持調度引擎架構的簡單性,所有相關的任務執行的處理,都是基于當前表(熱表),所以為了能保障被結轉的冷數據和熱數據一樣支持所有操作,冷數據被操作時會從冷數據表恢復至熱數據表,從而實現與熱數據相同的效果。
4、開放能力
開放API:通過Http協議進行開放,支持任務配置管理、任務實例操作、狀態查詢、日志查詢等能力,通過藏經閣進行開放來服務業務
開放事件:基于JDQ異步消息的方式將任務狀態、實例狀態進行開放,聯動業務個性化處理。狀態發生變更及時同步,確保業務觸達的及時性
三、未來規劃
Buffalo調度系統仍在持續的優化和迭代升級,不僅提供更好的用戶體驗、更極致的性能,也包括容器化能力、插件化擴展能力、開放能力、精細化的資源管理能力等,希望大家提出更好的想法和建議,一起打造穩定、高效、易用的調度平臺。
審核編輯 黃宇
-
調度系統
+關注
關注
0文章
43瀏覽量
9489 -
架構
+關注
關注
1文章
514瀏覽量
25470 -
DAG
+關注
關注
0文章
17瀏覽量
8155
發布評論請先 登錄
相關推薦
評論