EasySchedulerr大資料排程系統架構分析
導語
EasyScheduler是易觀平台自主研發的大資料分布式排程系統。主要解決資料研發ETL 錯綜複雜的依賴關系,而不能直覺監控任務健康狀态等問題。EasyScheduler以DAG流式的方式将Task組裝起來,可實時監控任務的運作狀态,同時支援重試、從指定節點恢複失敗、暫停及Kill任務等操作。
背景
任務排程系統在大資料平台當中是一個核心的基礎設施,由于資料處理流程常常具有很長的依賴鍊條,是以依賴單機的crontab等單純依賴時間排程的方式,往往存在很大的弊端,如依賴不清晰,出錯難以查找等問題,是以,我們調研了市面上流行的排程系統
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLyUFVNp3aU1UMJR0T4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLxETO4AzNxATM3IjMxgTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
鑒于易觀日處理資料30TB,複雜的 ETL依賴關系,我們開發了易觀自己的大資料分布式排程系統EasyScheduler。
總架構設計
EasyScheduler設計圍繞四個服務展開,UI、Web、Server和Alert。
- UI : 使用易觀封裝的Vue及jsplumb元件開發
- Web:使用SpringBoot提供Rest Api和UI分離互動
- Server : Scheduler排程及分布式任務執行引擎
- Alert:告警微服務
以下将詳細介紹Server的設計思想和遇到的問題
去中心化vs 中心化
中心化思想
中心化的設計理念比較簡單,分布式叢集中的節點按照角色分工,大體上分為兩種角色:
- Master的角色主要負責任務分發并監督Slave的健康狀态,可以動态的将任務均衡到Slave上,以緻Slave節點不至于“忙死”或”閑死”的狀态。
- Worker的角色主要負責任務的執行工作并維護和Master的心跳,以便Master可以配置設定任務給Slave。
中心化思想設計存在的問題:
- 一旦Master出現了問題,則群龍無首,整個叢集就崩潰。為了解決這個問題,大多數Master/Slave架構模式都采用了主備Master的設計方案,可以是熱備或者冷備,也可以是自動切換或手動切換,而且越來越多的新系統都開始具備自動選舉切換Master的能力,以提升系統的可用性。
- 另外一個問題是如果Scheduler在Master上,雖然可以支援一個DAG中不同的任務運作在不同的機器上,但是會産生Master的過負載。如果Scheduler在Slave上,則一個DAG中所有的任務都隻能在某一台機器上進行作業送出,則并行任務比較多的時候,Slave的壓力可能會比較大。
去中心化
去中心化設計裡,通常沒有Master/Slave的概念,所有的角色都是一樣的,地位是平等的,全球網際網路就是一個典型的去中心化的分布式系統,聯網的任意節點裝置down機,都隻會影響很小範圍的功能。
去中心化設計的核心設計在于整個分布式系統中不存在一個差別于其他節點的”管理者”,是以不存在單點故障問題。但由于不存在” 管理者”節點是以每個節點都需要跟其他節點通信才得到必須要的機器資訊,而分布式系統通信的不可靠行,則大大增加了上述功能的實作難度。
實際上,真正去中心化的分布式系統并不多見。反而動态中心化分布式系統正在不斷湧出。在這種架構下,叢集中的管理者是被動态選擇出來的,而不是預置的,并且叢集在發生故障的時候,叢集的節點會自發的舉行"會議"選舉新的"管理者"主持工作。最典型的案例就是ZooKeeper及Go語言實作的Etcd。
EasyScheduler的去中心化是Master/Worker注冊到Zookeeper中,實作Master叢集和Worker叢集無中心,并使用Zookeeper分布式鎖來選舉其中的一台Master或Worker為“管理者”來執行任務。
分布式鎖實踐
EasyScheduler使用Zookeeper分布式鎖來實作同一時刻隻有一台Master執行Scheduler,或者隻有一台Worker執行任務的送出。
擷取分布式鎖的核心流程算法如下:
EasyScheduler中Scheduler線程分布式鎖實作流程圖:
線程不足,循環等待問題
- 如果一個DAG中沒有子流程,則如果Command中的資料條數大于線程池設定的門檻值,則直接流程等待或失敗。
- 如果一個大的DAG中嵌套了很多子流程,如下圖:
EasySchedulerr大資料排程系統架構分析 則會産生“死等”狀态。MainFlowThread等待SubFlowThread1結束,
SubFlowThread1等待SubFlowThread2結束,SubFlowThread2等待SubFlowThread3結束,而SubFlowThread3等待線程池有新線程,則整個DAG流程不能結束,進而其中的線程也不能釋放。這樣就形成的子父流程循環等待的狀态。此時除非啟動新的Master來增加線程來打破這樣的”僵局”,否則排程叢集将不能再使用。
對于啟動新Master來打破僵局,似乎有點差強人意,于是我們提出了以下三種方案來降低這種風險:
- 計算所有Master的線程總和,然後對每一個DAG需要計算其需要的線程數,也就是在DAG流程執行之前做預計算。因為是多Master線程池,是以總線程數不太可能實時擷取。
- 對單Master線程池進行判斷,如果線程池已經滿了,則讓線程直接失敗。
- 增加一種資源不足的Command類型,如果線程池不足,則将主流程挂起。這樣線程池就有了新的線程,可以讓資源不足挂起的流程重新喚醒執行。
注意:Master Scheduler線程在擷取Command的時候是FIFO的方式執行的。
于是我們選擇了第三種方式來解決線程不足的問題。
容錯設計
EasyScheduler容錯設計依賴于Zookeeper的Watcher機制,實作原理如圖:
Master監控其他Master和Worker的目錄,如果監聽到remove事件,則會根據具體的業務邏輯進行流程執行個體容錯或者任務執行個體容錯。
Master容錯流程圖:
ZooKeeper Master容錯完成之後則重新由EasyScheduler中Scheduler線程排程,周遊 DAG 找到”正在運作”和“送出成功”的任務,對”正在運作”的任務監控其任務執行個體的狀态,對”送出成功”的任務需要判斷Task Queue中是否已經存在,如果存在則同樣監控任務執行個體的狀态,如果不存在則重新送出任務執行個體。
Worker容錯流程圖:
Master Scheduler線程一旦發現任務執行個體為” 需要容錯”狀态,則接管任務并進行重新送出。
注意:由于” 網絡抖動”可能會使得節點短時間内失去和zk的心跳,進而發生節點的remove事件。對于這種情況,我們使用最簡單的方式,那就是節點一旦和zk發生逾時連接配接,則直接将Master或Worker服務停掉。
Logback和gRPC實作日志通路
由于Web和Worker不一定在同一台機器上,是以檢視日志不能像查詢本地檔案那樣。有兩種方案:
- 将日志放到ES搜尋引擎上
-
通過gRPC通信擷取遠端日志資訊
介于考慮到盡可能的EasyScheduler的輕量級性,是以選擇了gRPC實作遠端通路日志資訊。
EasySchedulerr大資料排程系統架構分析
我們使用自定義Logback的FileAppender和Filter功能,實作每個任務執行個體生成一個日志檔案。
FileAppender實作如下:
以…/流程定義id/流程執行個體id/任務執行個體id.log的形式生成日志。
過濾比對以TaskLogInfo開始的線程名稱:
總結
本章從排程出發,介紹了易觀自主研發的大資料分布式排程系統。
EasyScheduler在易觀資料平台起着中流砥柱的作用。本章着重介紹了EasyScheduler的架構原理及實作思路。