背景
最近一直忙於對數據進行清洗及業務數據輸出,構建了大量的hadoop、hive等定時任務,這些任務存在依賴關係,任務A是任務B的基礎數據生產者,但且叫做B依賴A,那麼B必須在A之後運行(複雜的依賴關係可以查看下圖),同時,這些任務分散到各個系統中,僅僅依靠linux的crontab
,或者開發語言內的定時框架,不能更好的維護、管理越來越多的任務,因此,我需要一個可以方便調度、管理的任務中心平臺,但僅限於管理和調度,不對單個任務做分佈式的計算,所以,基於此做了一個簡單的實現。
目的
- 實現分佈式調度任務
- 實現負載均衡
- 實現任務的依賴關係管理,被依賴任務可自動觸發依賴任務的執行
- 實現方便添加、刪除、觸發任務等
- 實現對任務的監控、告警
- 調度中心必須高可用
架構設計
- 整體設計
使用後臺管理系統申請分組,創建任務等。任務創建好後,使用第三方組件(robfig/cron)做定時任務的觸發,任務觸發後,將任務數據包裝,丟進Redis的隊列中,客戶端通過接口消費Redis隊列數據。在任務觸發到丟進Redis隊列之間這個時間段,可以做依賴關係、任務狀態、負載均衡等等操作,以決定是否下發此任務,或者選擇客戶端某個節點執行。客戶端獲取到任務消息後,負責執行任務,上報任務狀態及上報節點負載情況。 - 模塊
- 任務調度模塊
- api模塊(支持rpc、http等)
- client模塊(支持衆多語言,如Go、Java、Python、Shell等)
- web後臺管理模塊
- 內部定時任務
架構設計圖如下
數據庫設計
- task:任務表
- task_prev:前置任務任務表
- job:觸發的作業表
- job_state:作業執行狀態表
- group:分組表,一般以項目或者團隊分組
- node:用戶節點表
Redis設計
- tsc:t:i:{tid}:數據庫任務對應cron裝配的任務ID,結構string
- tsc:j:q:{tid}:{node}:任務隊列,結構list
- tsc:t:j:l:{tid}:{date}:任務執行中鎖,結構string
- tsc:w:s:{tid}:{date}:後置任務列表,結構set
- tsc:w:s:l:{tid}:{date}:後置任務表操作鎖,結構string
核心代碼實現
- 任務調度
//檢驗是否有任務已經在運行
exists, err := existsJob(t.Tid, t.TaskDate)
if err != nil {
fmt.Println(fmt.Sprintf("task job exists err,jobId:%d,%v", jobId, err))
saveJobState(jobId, domain.StateInnerFailed)
return jobId
}
if exists {
fmt.Println(fmt.Sprintf("task job exists,jobId:%d", jobId))
saveJobState(jobId, domain.StateDuplicated)
return jobId
}
//負載均衡,目前簡單做成隨機,後續根據任務數量、cpu、內存等節點負載情況做優化
targetIp := ips[rand.Intn(len(ips))]
key := fmt.Sprintf(db.TaskJobQueue, t.gid, targetIp)
t.JobId = jobId
value, err := json.Marshal(t)
if err != nil {
fmt.Println(fmt.Sprintf("serialization job err,job_id:%d,%v", jobId, err))
saveJobState(jobId, domain.StateInnerFailed)
return jobId
}
err = db.RDB.RPush(context.Background(), key, value).Err()
if err != nil {
fmt.Println(fmt.Sprintf("add job to queue err, job_id: %d,%v", jobId, err))
saveJobState(jobId, domain.StateInnerFailed)
return jobId
}
總結
由於時間有限,花了兩天時間寫完了大概的代碼,項目使用go語言開發,本人一直使用go刷lc,對go情有獨鍾,當然,以目前的情況看,本人go代碼寫的並不夠美觀,但並不影響這個項目的設計初衷。目前待做的事情很多,如權限代碼的加入,負載均衡的完善,日誌的收集,監控告警的實現等等,後面有時間慢慢實現吧。查看源碼請移步 jackmanwu/task-schedule-center