1.目前etl的fetch task策略是基於任務子孫任務數和任務優先級獲得task list
2.然后遍歷task list 查看任務是否具備執行條件
- 集群資源校驗(yarn/hdfs)<如果這里有性能瓶頸,可以抽出來做公共接口map,每10s更新一次>
- 數據是否准備好(僅mysql task具備),解決主從延遲問題
- 任務開始時間
- 任務的父任務是否都執行成功
3.每10s fetch一次task,遍歷一次基於<2>的邏輯
我們把任務的父任務執行狀態判斷放到最后是想降低數據庫查詢成本(如果沒放到最后,可以在exec_log表中維護一個依賴是否校驗的狀態去動態變更來減少數據庫輪訓查找成本)
我們如何避免,如 a->b->c 依賴關系,a還沒完成又去校驗b,b又沒通過,又去校驗c這種情況呢(如果此樹較大,我們又是基於子孫任務數排序的話,會出現這種無謂遍歷數據庫的情況)。如果我們沒有維護全局樹及樹中各任務的狀態的話(成本較高,要時刻保證內存中的樹與mysql表的任務狀態同步)。
我們可以這么做(較少數據庫的無謂遍歷),在任務初始化時把任務依賴的dag加載的map中,並只維護任務與其一級子任務的關系如(<1,[2,3,4]> 父任務id:1,子任務id:2,3,4),然后在任務a校驗沒通過時,把a的一級子任務加入到list(此處不能放入set中,以為不能使用去重的集合,一個子任務可能會有多個父任務)中,依次遍歷按照如此邏輯,在這一輪遍歷結束后清空list。(或者維護全局list,在此任務校驗通過后,從set清除此任務的一級子任務)---此種策略適用於只基於子孫任務數的排序方式,如果還有基於權重的排序並且權重只更新了子任務而沒有更新此子任務的上游所有父任務就會出現嚴重問題
索性不如在每次fetch時就拿出子與父的map關系及當時的任務狀態,作為任務提交時的判斷,這樣每fetch一次只與數據庫交互一次
有如下兩張表,直接用sql可解決之前說的問題,注:<假如任務狀態status=0 為成功>
denpend <parent_id,child_id>
exec_log <task_id,status>
- depend 表的父id join exec_log 表的task_id,那么depend.child_id, depend.parent_id(=exec_log.task_id), exec_log.status(父任務的狀態)就出來了,group by depend.child_id ,sum(exec_log.status)=0 的depend.child_id可以跑,否則不可跑
此策略已上線,運行穩定!!!