XXL-JOB
【輕量級分布式任務調度平台】
(1) 基本介紹
XXL-JOB
是一個輕量級分布式任務調度平台,主打特點是平台化,易部署,開發迅速、學習簡單、輕量級、易擴展,代碼仍在持續更新中。
-
調度中心
: 任務調度控制台,平台自身並不承擔業務邏輯,只是負責任務的統一管理和調度執行,並且提供任務管理平台 -
執行器
: 負責接收“調度中心”的調度並執行,可直接部署執行器,也可以將執行器集成到現有業務項目中。 通過將任務的調度控制和任務的執行解耦,業務使用只需要關注業務邏輯的開發。 -
XXL-JOB
主要提供了任務的動態配置管理、任務監控和統計報表以及調度日志幾大功能模塊,支持多種運行模式和路由策略,可基於對應執行器機器集群數量進行簡單分片數據處理。
(2) 框架源碼及文檔
源碼地址:
文檔地址:
(3)XXL-JOB的特性
- 1、簡單:支持通過
Web頁面
對任務進行CRUD
操作,操作簡單,一分鍾上手; - 2、動態:支持_動態修改任務狀態、啟動/停止任務,以及終止運行中任務,即時生效_;
- 3、調度中心HA(中心式):調度采用
中心式設計
,調度中心自研調度組件並支持集群部署
,可保證調度中心HA; - 4、執行器HA(分布式):任務分布式執行,任務"執行器"支持集群部署,可保證任務執行HA;
- 5、注冊中心: 執行器會周期性自動注冊任務, 調度中心將會自動發現注冊的任務並觸發執行。也支持手動錄入執行器地址;
- 6、彈性擴容縮容:一旦有新執行器機器上線或者下線,下次調度時將會重新分配任務;
- 7、路由策略:執行器集群部署時提供豐富的路由策略,包括:_第一個、最后一個、輪詢、隨機、一致性HASH、最不經常使用、最近最久未使用、故障轉移、忙碌轉移_等;
- 8、故障轉移:任務路由策略選擇_故障轉移_情況下,如果執行器集群中某一台機器故障,將會自動Failover切換到一台正常的執行器發送調度請求。
- 9、阻塞處理策略:調度過於密集執行器來不及處理時的處理策略,策略包括:單機串行(默認)、丟棄后續調度、覆蓋之前調度;
- 10、任務超時控制:支持_自定義任務超時時間_,任務運行超時將會主動中斷任務;
- 11、任務失敗重試:支持_自定義任務失敗重試次數_,當任務失敗時將會按照預設的失敗重試次數主動進行重試;其中分片任務支持分片粒度的失敗重試;
- 12、任務失敗警告:默認提供郵件方式失敗告警,同時預留擴展接口,可方便的擴展短信、釘釘等告警方式;
- 13、分片廣播任務:執行器集群部署時,任務路由策略選擇
分片廣播
情況下,一次任務調度將會廣播觸發集群中所有執行器執行一次任務,可根據分片參數開發分片任務; - 14、動態分片:分片廣播任務以執行器為維度進行分片,支持動態擴容執行器集群從而動態增加分片數量,協同進行業務處理;在進行大數據量業務操作時可顯著提升任務處理能力和速度。
- 15、事件觸發:除了
Cron方式
和任務依賴方式
觸發任務執行之外,支持基於事件的觸發任務方式。調度中心提供觸發任務單次執行的API服務,可根據業務事件靈活觸發
(4) XXL-JOB架構圖
最新版本架構圖:
xxl-job其實也是在quartz的基礎上實現的,但是修改了任務調度的模式,並且任務調度采用注冊和RPC調用方式來實現。
管理后台頁面:
(5) XXL-JOB原理解析
2.1.0版本前核心調度模塊都是基於quartz
框架,2.1.0版本開始自研調度組件,移除quartz
依賴 ,使用時間輪調度。
(RPC的底層變化, 2.0.1 使用的是Jetty服務的RPC, 2.0.2 使用的Nettty服務的RPC)
(5.1) 定時觸發任務是如何實現的?:使用時間輪實現
xxl_job_info
表是記錄定時任務的db表,里面有個trigger_next_time(Long)
字段,表示下一次觸發的時間點任務時間被修改 / 每一次任務觸發后,可以根據cronb
表達式計算下一次觸發時間戳:
Date nextValidTime = new CronExpression(jobInfo.getJobCron()).getNextValidTimeAfter(new Date()))
更新trigger_next_time
字段- 定時執行任務邏輯:
- 定時任務
scheduleThread
:不斷從db
把5秒
內要執行的任務讀出,立即觸發 / 放到時間輪等待觸發,並更新trigger_next_time
- 獲取當前時間
now
- 輪詢
db
,找出trigger_next_time
在距now 5秒
內的任務
3.1 對到達now時間后的任務(超出now 5秒外)
(1) 直接跳過不執行;
(2) 重置trigger_next_time
3.2 對到達now
時間后的任務(超出now
5秒內)
(1) 開線程執行觸發邏輯;
(2) 若任務下一次觸發時間是在5秒內,則放到時間輪內(Map<Integer, List>秒數(1-60) => 任務id列表);
(3) 重置trigger_next_time
3.3 對未到達now
時間的任務
(1)直接放到時間輪內;
(2)重置trigger_next_time
- 定時任務
ringThread
:時間輪實現到點觸發任務
4.1 時間輪數據結構:Map<Integer, List<Integer>> key
是秒數(1-60)
,value
是任務id
列表
- 獲取當前時間秒數
- 從時間輪內移出當前秒數前2個秒數(避免處理耗時太長,跨過刻度,向前校驗一個刻度)的任務列表id,一一觸發任務;
- 定時任務
(5.2) 如何避免集群中的多個服務器同時調度任務?
當xxl-job應用本身集群部署(實現高可用HA)時,如何避免集群中的多個服務器同時調度任務?
通過mysql悲觀鎖實現分布式鎖(for update語句)
setAutoCommit(false)
關閉隱式自動提交事務,啟動事務select lock for update
(顯式排他鎖,其他事務無法進入&無法實現for update
)- 讀
db
任務信息 -> 拉任務到內存時間輪 -> 更新db
任務信息 commit
提交事務,同時會釋放for update
的排他鎖(悲觀鎖)
(5.3) 任務執行器注冊中心是如何實現的?
使用db表xxl_job_group記錄下執行器的信息:
執行器AppName、執行器名稱title、執行器地址列表address_list(多地址逗號分隔)
(5.4) 如何實現任務執行器的路由?
- 執行器集群部署時提供豐富的路由策略,包括:
第一個、最后一個、輪詢、隨機、一致性HASH、最不經常使用、最近最久未使用、故障轉移、忙碌轉移等;
- 第一個、最后一個、輪詢、隨機:都是簡單讀
address_list
即可 - 一致性HASH:
TreeSet
實現一致性hash
算法 - 最不經常使用、最近最久未使用:
HashMap、LinkedHashMap
- 故障轉移:遍歷
address_list
獲取address
時,逐個檢查該address
的心跳(請求返回狀態);只有心跳正常的address
才返回使用 - 忙碌轉移:遍歷
address_list
獲取address
時,逐個檢查該address
是否忙碌(請求返回狀態);只有狀態為idle
的address
才返回使用
(5.5) 如何實現任務分片、並行執行?
- 拉出任務的執行機器列表,逐個設置
index / total
,把index / total
分發到任務執行器 - 任務執行器可根據
index / total
參數開發分片任務
(6)XXL-JOB任務調度流程
1:XXL-Jobadmin平台創建執行器(Job實際執行地址)
2:XXL-Jobadmin平台新建任務,填寫對應的執行器
3:Job服務器代碼中,使用JobHandler表示該類為Job執行方法
4:當任務執行的時候,會現在XXL-Jobadmin調度平台先執行一次,獲取任務中的執行器,然后去對應的執行器地址服務器,執行對應的任務
輕量級分布式任務調度平台XXL-JOB系列
輕量級分布式任務調度平台(一、 XXL-JOB介紹、原理、工作流程)
輕量級分布式任務調度平台(二、XXL-JOB環境搭建集成springboot)