開源:XXL-JOB-分布式任務調度平臺

《分布式任務調度平臺XXL-JOB》

一、簡介

1.1 概述

XXL-JOB是一個輕量級分布式任務調度框架,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。現已開放源代碼并接入多家公司線上產品線,開箱即用。

1.2 特性

  • 1、簡單:支持通過Web頁面對任務進行CRUD操作,操作簡單,一分鐘上手;
  • 2、動態:支持動態修改任務狀態、暫停/恢復任務,以及終止運行中任務,即時生效;
  • 3、調度HA:“調度中心”基于集群Quartz實現,可保證調度中心HA;
  • 4、任務HA:任務"執行器"支持集群部署,可保證任務執行HA;
  • 5、任務Failover:執行器集群部署時,調度失敗時將會平滑切換執行器進行Failover;
  • 6、一致性:“調度中心”通過DB鎖保證集群分布式調度的一致性, 一次任務調度只會觸發一次執行;
  • 7、自定義任務參數:支持在線配置調度任務入參,即時生效;
  • 8、調度線程池:調度系統多線程觸發調度運行,確保調度精確執行,不被堵塞;
  • 9、執行日志:支持在線查看調度結果,并且查看完整的執行日志;
  • 10、郵件報警:任務失敗時支持郵件報警,支持配置多郵件地址群發報警郵件;
  • 11、支持登錄驗證;
  • 12、GLUE:提供Web IDE,支持在線開發任務邏輯代碼,動態發布,實時編譯生效,省略部署上線的過程。支持30個版本的歷史版本回溯。
  • 13、數據加密:調度中心和執行器之間的通訊進行數據加密,提升調度信息安全性;
  • 14、任務依賴:支持配置子任務依賴,當父任務執行結束且執行成功后將會主動觸發一次子任務的執行, 多個子任務用逗號分隔;
  • 15、推送maven中央倉庫: 將會把最新穩定版推送到maven中央倉庫, 方便用戶接入和使用;
  • 16、任務注冊: 執行器會周期性自動注冊任務, 調度中心將會自動發現注冊的任務并觸發執行。

1.3 發展

于2015年中,我在github上創建XXL-JOB項目倉庫并提交第一個commit,隨之進行系統結構設計,UI選型,交互設計……

于2015-11月,XXL-JOB終于REALEASE了第一個大版本V1.0, 隨后我將之發布到OSCHINA,XXL-JOB在OSCHINA上獲得了@紅薯的熱門推薦,同期分別達到了OSCHINA的“熱門動彈”排行第一和git.oschina的開源軟件月熱度排行第一,在此特別感謝紅薯,感謝大家的關注和支持。

于2015-12月,我將XXL-JOB發表到我司內部知識庫,并且得到內部同事認可。

于2016-01月我司展開XXL-JOB的內部接入和定制工作,在此感謝袁某和尹某兩位同事的貢獻,同時也感謝內部其他給與關注與支持的同事。

我司大眾點評目前已接入XXL-JOB,內部別名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入應用推薦升級最新版本)。據最新統計, 自2016-01-21接入至2017-02-07期間,該系統已調度約30萬次,表現優異。新接入應用推薦使用最新版本,因為經過數個大版本的更新,系統的任務模型、UI交互模型以及底層調度通訊模型都有了較大的優化和提升,核心功能更加穩定高效。

至今,XXL-JOB已接入多家公司的線上產品線,接入場景如電商業務,O2O業務和大數據作業等,截止2016-07-19為止,XXL-JOB已接入的公司包括不限于:

  • 1、大眾點評;
  • 2、山東學而網絡科技有限公司;
  • 3、安徽慧通互聯科技有限公司;
  • 4、人人聚財金服;
  • 5、上海棠棣信息科技股份有限公司
  • 6、運滿滿
  • 7、米其林 (中國區)
  • 8、媽媽聯盟
  • 9、九櫻天下(北京)信息技術有限公司
  • 10、萬普拉斯科技有限公司(一加手機)
  • 11、上海億保健康管理有限公司
  • 12、海爾馨廚 (海爾)
  • 13、河南大紅包電子商務有限公司
  • 14、成都順點科技有限公司
  • 15、深圳市怡亞通
  • 16、深圳麥亞信科技股份有限公司
  • 17、上海博瑩科技信息技術有限公司
  • ……</pre>

    歡迎大家的關注和使用,XXL-JOB也將擁抱變化,持續發展。

    1.4 下載

    源碼地址 (將會在兩個git倉庫同步發布最新代碼)

    中央倉庫地址 (最新Release版本)

    <!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->
    <dependency>
      <groupId>com.xuxueli</groupId>
      <artifactId>xxl-job-core</artifactId>
      <version>1.5.2</version>
    </dependency>

    Download: 歷史Release版本下載位置如下圖所示,請自行前往進行選擇和下載。

    1.5 環境

    • Servlet/JSP Spec:3.0/2.2
    • Jdk:1.7+
    • Tomcat:7+
    • Maven:3+
    • Mysql:5.5+

    二、快速入門

    2.1 初始化“調度數據庫”

    請下載項目源碼并解壓,獲取 "調度數據庫初始化SQL腳本"(腳本文件為: 源碼解壓根目錄\xxl-job\db\tables_xxl_job.sql) 并執行即可。正常情況下,應該生成如下圖所示16張表;

    調度中心集群情況下,集群節點務必連接同一個mysql實例;如果mysql做主從,調度中心集群節點務必強制走主庫;

    2.2 編譯源碼

    解壓源碼,按照maven格式將源碼導入IDE, 使用maven進行編譯即可,源碼結構如下圖所示:

  • xxl-job-admin:調度中心
  • xxl-job-core:公共依賴
  • xxl-job-executor-example:執行器(可直接使用該執行器,也可以將現有項目改造成執行器使用)</pre>

    2.3 配置部署“調度中心”

    調度中心項目:xxl-job-admin
    作用:統一管理任務調度平臺上調度任務,負責觸發調度執行。
    • A:配置調度中心JDBC鏈接:

      請在下圖所示位置配置jdbc鏈接地址,鏈接地址請保持和 2.1章節 所創建的調度數據庫的地址一致。

    • B:配置報警郵箱和登陸賬號:

      請在下圖所示位置,設置自己的報警郵件發送郵箱和登陸賬號密碼。

    • C:配置“調度中心”任務執行結果回調端口:

      由于“調度中心”和“執行器”部署在不同項目中,“執行器”會請求該端口回調通知任務執行結果。如下圖所示,默認回調服務端口號為8888。(此端口除非與現有端口沖突,可自行修改,否則可忽視)

    部署項目:如果已經正確進行上述配置,可將項目編譯打war包并部署到tomcat中。

    訪問鏈接:http://localhost:8080/xxl-job-admin/ ,登陸界面如下圖所示

    至此“調度中心”項目已經部署成功。

    2.4 配置部署“執行器項目”

    “執行器”項目:xxl-job-executor-example
    作用:負責接收“調度中心”的調度并執行;
    • A:配置Jdbc鏈接 :(執行器 "DbRegistHelper" 和 "DbGlueLoader" 依賴JDBC配置; 推薦將其抽象為RPC遠程服務, 可取消對JDBC的依賴)

    請在下圖所示位置配置jdbc鏈接地址,鏈接地址請保持和 2.1章節 所創建的調度數據庫的地址一致。

    • B:配置“執行器”

    1、JobHandler 掃描路徑
    2、執行器端口 "port": 默認9999
    3、執行器注冊器 "registHelper": 默認使用系統提供的 "DbRegistHelper"(依賴JDBC), 推薦將其改為公共的RPC服務
    3、GLUE源碼加載器 "glueLoader": 默認使用系統提供的 "DbGlueLoader"(依賴JDBC), 推薦將其改為公共的RPC服務
    4、XXL-JOB公共數據源 "xxlJobDataSource": 僅在啟動 "DbRegistHelper" 或 "DbGlueLoader" 時才需要, 否則可刪除

    執行器端口:由于“調度中心”和“執行器”部署在不同項目,“調度中心”會請求該端口觸發任務執行。如上圖所示,默認的“執行器”端口是9999,如果與系統現有端口沖突可自行修改,如若不沖突,可忽略。

    部署項目:

    至此“執行器”項目已經部署結束。

    2.5 開發第一個任務“Hello World”

    本示例為新建一個“GLUE模式任務”(“GLUE模式任務”的執行代碼支持托管到調度中心在線維護,相比“Bean模式任務”需要在執行器項目開發部署上線,更加簡便輕量)。更多有關任務的詳細配置,請查看“章節三:任務詳解”。

    前提:請確認“調度中心”和“執行器”項目已經成功部署并啟動;

    • 步驟一(新建任務):

      登陸調度中心,點擊下圖所示“新建任務”按鈕,新建示例任務。然后,參考下面截圖中任務的參數配置,點擊保存。

    • 步驟二(GLUE任務開發):

      請點擊下圖中所示“GLUE入口按鈕”,進入“GLUE編輯器開發界面”,見下圖。GLUE任務默認已經初始化了示例任務代碼,即打印Hello World。 (GLUE實際上是一段繼承自IJobHandler的Java類代碼,它在執行器項目中運行,可使用@Resource/@Autowire注入執行器里中的其他服務,詳細介紹請查看第三章節)

    • 步驟三(觸發執行):

      點擊下圖所示“執行”按鈕,可手動觸發一次任務執行(通常情況下,通過配置Cron表達式進行任務調度出發)。

    • 步驟四(查看日志):

      點擊圖2.5F所示“日志”按鈕,可前往任務日志界面查看任務日志。 在如圖2.5G的任務日志界面中,可查看任務調度狀態,執行器接收到調度請求后的執行狀態。 同時,點擊如圖2.5G中的“執行日志”按鈕,可以查看本此調度在執行器端的完整執行日志,完整執行日志如圖2.5H。

    (圖2.5F:“調度中心”管理管理界面,任務日志入口)

    (圖2.5G:“調度中心”管理管理界面,任務日志入口)

    (圖2.5H:“調度中心”管理管理界面,任務日志入口)

    三、任務詳解

    配置屬性詳細說明:

  • 執行器:任務的綁定的執行器,任務觸發調度時將會自動發現注冊成功的執行器, 實現任務自動發現功能; 另一方面也可以方便的進行任務分組。每個任務必須綁定一個執行器, 可在 "執行器管理" 進行設置;
  • 描述:任務的描述信息,便于任務管理;
  • 執行器地址:執行器接受任務調度的地址,格式為“IP:Port”,支持配置多個地址進行Failover,當存在多個地址時用逗號分隔,格式為“IP1:Port,IP2:Port...”
  • Cron:觸發任務執行的Cron表達式;
  • JobHandler + GLUE復選框: BEAN模式任務:不選中GLUE復選框,JobHandler輸入框為必填項,需要輸入該任務對應的JobHandler的名稱,即執行器中新開發的JobHandler類“@JobHander”注解自定義的value值; GLUE模式任務:選中GLUE復選框,JobHandler輸入框被禁用,不必輸入,因為此時任務邏輯維護在線上。
  • 執行參數:任務執行所需的參數,多個參數時用逗號分隔,任務執行時將會把多個參數抓換成數組傳入;
  • 報警郵件:任務調度失敗時郵件通知的郵箱地址,支持配置多郵箱地址,配置多個郵箱地址時用逗號分隔;
  • 負責人:任務的負責人;
  • 子任務Key:每個任務都擁有一個唯一的任務Key(任務Key可以從任務列表獲取),當本任務執行結束并且執行成功時,將會觸發子任務Key所對應的任務的一次主動調度。</pre>

    3.1 BEAN模式任務

    Bean模式任務:任務邏輯以JobHandler的形式存在于“執行器”所在項目中,開發流程如下:

    • 步驟一:執行器項目中,開發JobHandler
      • 1、 新建一個繼承com.xxl.job.core.handler.IJobHandler的Java類;
      • 2、 該類被Spring容器掃描為Bean實例,如加“@Service注解”;
      • 3、 添加 “@JobHander(value="自定義jobhandler名稱")”注解,注解的value值為自定義的JobHandler名稱,該名稱對應的是調度中心新建任務的JobHandler屬性的值。 (可參考xxl-job-executor-example項目中的DemoJobHandler,見下圖)
      </li> </ul>

      • 步驟二:調度中心,新建調度任務并配置(BEAN模式)

      參考上文“配置屬性詳細說明”對新建的任務進行參數配置,需要注意的是“JobHandler + GLUE復選框”任務屬性,需要按照“GLUE模式”任務進行配置;

      3.2 GLUE模式任務

      GLUE模式任務:任務邏輯以GLUE代碼的形式存儲在DB中,支持通過Web IDE在線更新,實時編譯和生效,因此不需要指定JobHandler。開發流程如下:

      • 步驟一:調度中心,新建調度任務并配置(GLUE模式)

      參考上文“配置屬性詳細說明”對新建的任務進行參數配置,需要注意的是“JobHandler + GLUE復選框”任務屬性,需要按照“GLUE模式”任務進行配置;

      開源:XXL-JOB-分布式任務調度平臺

      • 步驟二:開發GLUE代碼

      選中指定任務,點擊該任務右側“GLUE”按鈕(僅GLUE模式任務支持),將會前往GLUE任務的Web IDE界面,在該界面支持對任務代碼進行開發(當然也可以在IDE中開發完成后,復制粘貼到編輯中),可使用@Resource或@Autoward注解注入“執行器”項目中的Spring服務;

      版本回溯功能(支持30個版本的版本回溯):可參考下圖,選擇下拉框“版本回溯”,會列出該GLUE的更新歷史,選擇相應版本即可顯示該版本代碼,保存后GLUE代碼即回退到對應的歷史版本;

      四、任務管理

      4.0 配置執行器

      點擊進入"執行器管理"界面, 如下圖:

      1、"調度中心OnLine:"右側顯示在線的"調度中心"列表, 任務執行結束后, 將會以failover的模式進行回調調度中心通知執行結果, 避免回調的單點風險;
      2、"執行器列表" 中顯示在線的執行器列表, 可通過"OnLine 機器"查看對應執行器的集群機器。

      點擊按鈕 "+新增執行器" 彈框如下圖, 可新增執行器配置:

      執行器屬性說明

      AppName: 是每個執行器集群的唯一標示AppName, 執行器會周期性以AppName為對象進行自動注冊。可通過該配置自動發現注冊成功的執行器, 供任務調度時使用;
      名稱: 執行器的名稱, 因為AppName限制字母數字等組成,可讀性不強, 名稱為了提高執行器的可讀性;
      排序: 執行器的排序, 系統中需要執行器的地方,如任務新增, 將會按照該排序讀取可用的執行器列表;

      4.1 新建任務

      進入任務管理界面,點擊“新增任務”按鈕,在彈出的“新增任務”界面配置任務屬性后保存即可,可參考下圖:

      4.2 編輯任務

      進入任務管理界面,選中指定任務。點擊該任務右側“編輯”按鈕,在彈出的“編輯任務”界面更新任務屬性后保存即可,可參考下圖:

      4.3 編輯GLUE代碼

      該操作僅針對GLUE任務。

      GLUE任務開發:進入任務管理界面,選中指定任務。點擊該任務右側“GLUE”按鈕(僅GLUE模式任務支持),將會前往GLUE任務的Web IDE界面,在該界面支持對任務代碼進行開發(當然也可以在IDE中開發完成后,復制粘貼到編輯中)

      版本回溯功能(支持30個版本的版本回溯):可參考下圖,選擇下拉框“版本回溯”,會列出該GLUE的更新歷史,選擇相應版本即可顯示該版本代碼,保存后GLUE代碼即回退到對應的歷史版本;

      4.4 暫停/恢復任務

      可對任務進行“暫停”和“恢復”操作。 需要注意的是,此處的暫停/恢復僅針對任務的后續調度觸發行為,不會影響到已經觸發的調度任務,如需終止已經觸發的調度任務,可查看“4.8 終止運行中的任務”

      4.5 手動觸發一次調度

      點擊“執行”按鈕,可手動觸發一次任務調度,不影響原有調度規則。

      4.6 查看調度日志

      點擊“日志”按鈕,可以查看任務歷史調度日志。在歷史調入日志界面可查看每次任務調度的調度結果、執行結果等,點擊“執行日志”按鈕可查看執行器完整日志。

      調度日志,針對單次調度,屬性說明如下:

      • 執行器地址:任務執行的機器地址;
      • JobHandler:Bean模式表示任務執行的JobHandler名稱;
      • 任務參數:任務執行的入參;
      • 調度時間:調度中心,發起調度的時間;
      • 調度結果:調度中心,發起調度的結果,SUCCESS或FAIL;
      • 調度備注:調度中心,發起調度的備注信息,如地址心跳檢測日志等;
      • 執行時間:執行器,任務執行結束后回調的時間;
      • 執行結果:執行器,任務執行的結果,SUCCESS或FAIL;
      • 執行備注:執行器,任務執行的備注信息,如異常日志等;
      • 執行日志:任務執行過程中,業務代碼中打印的完整執行日志,見“4.7 查看執行日志”;

      4.7 查看執行日志

      點擊執行日志右側的 “執行日志” 按鈕,可跳轉至執行日志界面,可以查看業務代碼中打印的完整日志,如下圖;

      4.8 終止運行中的任務

      僅針對執行中的任務。 在任務日志界面,點擊右側的“終止任務”按鈕,將會向本次任務對應的執行器發送任務終止請求,將會終止掉本次任務,同時會清空掉整個任務執行隊列。

      任務終止時通過 "interrupt" 執行線程的方式實現, 將會觸發 "InterruptedException" 異常。因此如果JobHandler內部catch到了該異常并消化掉的話, 任務終止功能將不可用。

      因此, 如果遇到上述任務終止不可用的情況, 需要在JobHandler中應該針對 "InterruptedException" 異常進行特殊處理 (向上拋出) , 正確邏輯如下:

      try{
        // TODO
      } catch (Exception e) {
        if (e instanceof InterruptedException) {
      
        throw e;
      
      } logger.warn("{}", e); }</pre>

      4.9 刪除任務

      點擊刪除按鈕,可以刪除對應任務。

      五、總體設計

      5.1 源碼目錄介紹

    • /doc :文檔資料
    • /db :“調度數據庫”建表腳本
    • /xxl-job-admin :調度中心,項目源碼
    • /xxl-job-core :公共Jar依賴
    • /xxl-job-executor-example :執行器,Demo項目源碼(大家可以在該項目上進行開發,也可以將現有項目改造生成執行器項目)</pre>

      5.2 “調度數據庫”配置

      XXL-JOB調度模塊基于Quartz集群實現,其“調度數據庫”是在Quartz的11張集群mysql表基礎上擴展而成。

      XXL-JOB首先定制了Quartz原生表結構前綴(XXL_JOB_QRTZ_)。

      然后,在此基礎上新增了三張擴展表,如下: - XXL_JOB_QRTZ_TRIGGER_INFO:調度擴展信息表: 用于保存XXL-JOB調度任務的擴展信息,如任務分組、任務名、機器地址、執行器、執行入參和報警郵件等等; - XXL_JOB_QRTZ_TRIGGER_LOG:調度日志表: 用于保存XXL-JOB任務調度的歷史信息,如調度結果、執行結果、調度入參、調度機器和執行器等等; - XXL_JOB_QRTZ_TRIGGER_LOGGLUE:任務GLUE日志:用于保存GLUE更新歷史,用于支持GLUE的版本回溯功能;

      因此,XXL-JOB調度數據庫共計用于14張數據庫表。

      5.3 架構設計

      5.3.1 設計思想

      將調度行為抽象形成“調度中心”公共平臺,而平臺自身并不承擔業務邏輯,“調度中心”負責發起調度請求。

      將任務抽象成分散的JobHandler,交由“執行器”統一管理,“執行器”負責接收調度請求并執行對應的JobHandler中業務邏輯。

      因此,“調度”和“任務”兩部分可以相互解耦,提高系統整體穩定性和擴展性;

      5.3.2 系統組成

      • 調度模塊(調度中心) : 負責管理調度信息,按照調度配置發出調度請求,自身不承擔業務代碼。調度系統與任務解耦,提高了系統可用性和穩定性,同時調度系統性能不再受限于任務模塊; 支持可視化、簡單且動態的維管理調度信息,包括任務新建,更新,刪除,GLUE開發和任務報警等,所有上述操作都會實時生效,同時支持監控調度結果以及執行日志,支持執行器Failover。
      • 執行模塊(執行器) : 負責接收調度請求并執行任務邏輯。任務模塊專注于任務的執行等操作,開發和維護更加簡單和高效; 接收“調度中心”的執行請求、終止請求和日志請求等。

      5.3.3 架構圖

      5.4 調度模塊剖析

      5.4.1 quartz的不足

      Quartz作為開源作業調度中的佼佼者,是作業調度的首選。但是集群環境中Quartz采用API的方式對任務進行管理,從而可以避免上述問題,但是同樣存在以下問題: - 問題一:調用API的的方式操作任務,不人性化; - 問題二:需要持久化業務QuartzJobBean到底層數據表中,系統侵入性相當嚴重。 - 問題三:調度邏輯和QuartzJobBean耦合在同一個項目中,這將導致一個問題,在調度任務數量逐漸增多,同時調度任務邏輯逐漸加重的情況加,此時調度系統的性能將大大受限于業務; XXL-JOB彌補了quartz的上述不足之處。

      5.4.2 RemoteHttpJobBean

      常規Quartz的開發,任務邏輯一般維護在QuartzJobBean中,耦合很嚴重。XXL-JOB中“調度模塊”和“任務模塊”完全解耦,調度模塊中的所有調度任務使用同一個QuartzJobBean,即RemoteHttpJobBean。不同的調度任務將各自參數維護在各自擴展表數據中,當觸發RemoteHttpJobBean執行時,將會解析不同的任務參數發起遠程調用,調用各自的遠程執行器服務。

      這種調用模型類似RPC調用,RemoteHttpJobBean提供調用代理的功能,而執行器提供遠程服務的功能。

      5.4.3 調度中心HA(集群)

      基于Quartz的集群方案,數據庫選用Mysql;集群分布式并發環境中使用QUARTZ定時任務調度,會在各個節點會上報任務,存到數據庫中,執行時會從數據庫中取出觸發器來執行,如果觸發器的名稱和執行時間相同,則只有一個節點去執行此任務。

      # for cluster
      org.quartz.jobStore.tablePrefix = XXL_JOB_QRTZ_
      org.quartz.scheduler.instanceId: AUTO
      org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
      org.quartz.jobStore.isClustered: true
      org.quartz.jobStore.clusterCheckinInterval: 1000

      5.4.4 調度線程池

      默認線程池中線程的數量為10個,避免單線程因阻塞而引起任務調度延遲。

      org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
      org.quartz.threadPool.threadCount: 10
      org.quartz.threadPool.threadPriority: 5
      org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true

      XXL-JOB系統中業務邏輯在遠程執行器執行,調度中心每次調度僅僅負責一次調度請求,執行器會將請求存入執行隊列并且立即響應調度中心;相比直接在quartz的QuartzJobBean中執行業務邏輯,差別就像大象和羽毛;

      XXL-JOB調度中心中每個JOB邏輯非常 “輕”,單個JOB一次運行平均耗時基本在 "100ms" 之內(基本是網絡開銷);因此,可以保證使用有限的線程支撐大量的JOB并發運行;上面配置的10個線程至少可以支撐100個JOB正常運行;

      5.4.5 @DisallowConcurrentExecution

      XXL-JOB調度模塊的“調度中心”默認不使用該注解,即默認開啟并行機制,因為RemoteHttpJobBean為公共QuartzJobBean,這樣在多線程調度的情況下,調度模塊被阻塞的幾率很低,大大提高了調度系統的承載量。

      XXL-JOB的每個調度任務雖然在調度模塊是并行調度執行的,但是任務調度傳遞到任務模塊的“執行器”確實串行執行的,同時支持任務終止。

      5.4.6 misfire

      錯過了觸發時間,處理規則。 可能原因:服務重啟;調度線程被QuartzJobBean阻塞,線程被耗盡;某個任務啟用了@DisallowConcurrentExecution,上次調度持續阻塞,下次調度被錯過;

      quartz.properties中關于misfire的閥值配置如下,單位毫秒:

      org.quartz.jobStore.misfireThreshold: 60000

      Misfire規則: withMisfireHandlingInstructionDoNothing:不觸發立即執行,等待下次調度; withMisfireHandlingInstructionIgnoreMisfires:以錯過的第一個頻率時間立刻開始執行; withMisfireHandlingInstructionFireAndProceed:以當前時間為觸發頻率立刻觸發一次執行;

      XXL-JOB默認misfire規則為:withMisfireHandlingInstructionDoNothing

      CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getJobCron()).withMisfireHandlingInstructionDoNothing();
      CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();

      5.4.7 日志回調服務

      調度模塊的“調度中心”作為Web服務單獨部署,除此之外,內部嵌入jetty服務器提供日志回調服務。

      “執行器”在接收到任務執行請求后,執行任務,在執行結束之后會將執行結果回調通知“調度中心”,回調端口如下圖所示。

      開源:XXL-JOB-分布式任務調度平臺

      5.4.8 任務HA(Failover)

      執行器如若集群部署,調度中心將會感知到在線的所有執行器,如“127.0.0.1:9998,127.0.0.1:9999”。

      執行器集群部署,當調度中心每次發起調度請求時,會對執行器隨機排序,然后按照順序取對執行器發出心跳檢測請求,第一個檢測為存活狀態的執行器將會被選定并發送調度請求。

      調度成功后,可在日志監控界面查看“調度備注”,如下;

      “調度備注”可以查看執行器地址選擇日志,任務配置的地址“227.0.0.1:9999,127.0.0.1:9999”,首先對第一個執行器地址“227.0.0.1:9999”進行心跳檢測,心跳失敗因此跳過;然后對第二個執行器地址“127.0.0.1:9999”進行心跳檢測,心跳檢測成功,選定為“目標執行器”;然后對“目標執行器”發送調度請求,調度流程結束,等待執行器回調執行結果。

      5.4.9 調度日志

      調度中心每次進行任務調度,都會記錄一條任務日志,任務日志主要包括以下三部分內容:

      • 任務信息:包括“執行器地址”、“JobHandler”和“執行參數”等屬性,根據這些參數,可以精確的定位任務執行的具體機器和任務代碼;
      • 調度信息:包括“調度時間”、“調度結果”和“調度日志”等,根據這些參數,可以了解“調度中心”發起調度請求時具體情況。
      • 執行信息:包括“執行時間”、“執行結果”和“執行日志”等,根據這些參數,可以了解在“執行器”端任務執行的具體情況;

      開源:XXL-JOB-分布式任務調度平臺

      調度日志,針對單次調度,屬性說明如下:

      • 執行器地址:任務執行的機器地址;
      • JobHandler:Bean模式表示任務執行的JobHandler名稱;
      • 任務參數:任務執行的入參;
      • 調度時間:調度中心,發起調度的時間;
      • 調度結果:調度中心,發起調度的結果,SUCCESS或FAIL;
      • 調度備注:調度中心,發起調度的備注信息,如地址心跳檢測日志等;
      • 執行時間:執行器,任務執行結束后回調的時間;
      • 執行結果:執行器,任務執行的結果,SUCCESS或FAIL;
      • 執行備注:執行器,任務執行的備注信息,如異常日志等;
      • 執行日志:任務執行過程中,業務代碼中打印的完整執行日志,見“4.7 查看執行日志”;

      5.4.10 任務依賴

      原理:XXL-JOB中每個任務都對應有一個任務Key,同時,每個任務支持設置屬性“子任務Key”,因此,通過“任務Key”可以匹配任務依賴關系。

      當父任務執行結束并且執行成功時,將會根據“子任務Key”匹配子任務依賴,如果匹配到子任務,將會主動觸發一次子任務的執行。

      在任務日志界面,點擊任務的“執行備注”的“查看”按鈕,可以看到匹配子任務以及觸發子任務執行的日志信息,如無信息則表示未觸發子任務執行,可參考下圖。

      5.5 執行模塊剖析

      5.5.1 Bean模式任務

      開發步驟:見章節三; 原理:每個Bean模式任務都是一個Spring的Bean類實例,它被維護在“執行器”項目的Spring容器中。任務類需要加“@JobHander(value="名稱")”注解,因為“執行器”會根據該注解識別Spring容器中的任務。任務類需要繼承統一接口“IJobHandler”,任務邏輯在execute方法中開發,因為“執行器”在接收到調度中心的調度請求時,將會調用“IJobHandler”的execute方法,執行任務邏輯。

      5.5.2 GLUE模式任務

      開發步驟:見章節三; 原理:每個Glue任務的代碼,實際上是“一個繼承自“IJobHandler”的實現類的類代碼”,“執行器”接收到“調度中心”的調度請求時,會通過Groovy類加載器加載此代碼,實例化成Java對象,同時注入此代碼中聲明的Spring服務(請確保Glue代碼中的服務和類引用在“執行器”項目中存在),然后調用該對象的execute方法,執行任務邏輯。

      5.5.3 執行器

      執行器實際上是一個內嵌的Jetty服務器,默認端口9999。

      在項目啟動時,執行器會通過“@JobHander”識別Spring容器中“Bean模式任務”,以注解的value屬性為key管理起來。

      “執行器”接收到“調度中心”的調度請求時,如果任務類型為“Bean模式”,將會匹配Spring容器中的“Bean模式任務”,然后調用其execute方法,執行任務邏輯。如果任務類型為“GLUE模式”,將會加載GLue代碼,實例化Java對象,注入依賴的Spring服務(注意:Glue代碼中注入的Spring服務,必須存在與該“執行器”項目的Spring容器中),然后調用execute方法,執行任務邏輯。

      5.5.4 任務日志

      XXL-JOB會為每次調度請求生成一個單獨的日志文件,通過重寫LOG4J的Appender實現,“調度中心”查看執行日志時將會加載對應的日志文件。

      需要注意的是,“執行器”中日志Appender上配置的包名,需要覆蓋到所有任務(Bean模式 + GLUE模式)的包名,否則覆蓋不到的任務將不會生成日志文件。

      // 以下代碼見/xxl-job/xxl-job-executor-example/src/main/resources/log4j.xml文件
      <appender name="xxl-job" class="com.xxl.job.core.log.XxlJobFileAppender">
        <param name="filePath" value="/data/applogs/xxl-job/jobhandler/"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
      
        <param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%t]-[%M]-[%L]-[%p] %m%n"/>
      
      </layout> </appender> ... <logger name="com.xxl.job.executor.service.jobhandler" additivity="false"> <level value="INFO" /> <appender-ref ref="CONSOLE" /> <appender-ref ref="FILE" /> <appender-ref ref="xxl-job"/> </logger></pre>

      單獨日志文件存放的位置可在“執行器”的log.xml文件進行自定義,默認位置為項目磁盤根目錄下“/data/applogs/xxl-job/jobhandler/”;

      目錄格式為:/data/applogs/xxl-job/jobhandler/“格式化日期”/“數據庫調度日志記錄的主鍵ID.log”。

      5.6 通訊模塊剖析

      5.6.1 一次完整的任務調度通訊流程

    • 1、“調度中心”向“執行器”發送http調度請求: “執行器”中接收請求的服務,實際上是一臺內嵌jetty服務器,默認端口9999;
    • 2、“執行器”執行任務邏輯;
    • 3、“執行器”http回調“調度中心”調度結果: “調度中心”中接收回調的服務,實際上是一臺內嵌jetty服務器,默認端口8888;</pre>

      5.6.2 通訊數據加密

      調度中心與執行器之間使用RequestModel和ResponseModel兩個對象封裝調度請求參數和響應數據, 在進行通訊之前底層會將上述兩個對象對象序列化字節數組,最終轉化成16進制數據進行數據交互,從而達到數據加密的功能;

      5.7 任務注冊, 任務自動發現

      自v1.5版本之后, 任務取消了"任務執行機器"屬性, 改為通過任務注冊和自動發現的方式, 動態獲取遠程執行器地址并執行。

      AppName: 每個執行器機器集群的唯一標示, 任務注冊以 "執行器" 為最小粒度進行注冊; 每個任務通過其綁定的執行器可感知對應的執行器機器列表;
      Beat: 任務注冊心跳周期, 默認15s; 執行器以一倍Beat進行執行器注冊, 調度中心以一倍Beat進行動態任務發現; 注冊信息的失效時間被兩倍Beat; 
      注冊表: 見"XXL_JOB_QRTZ_TRIGGER_REGISTRY"表, "執行器" 在進行任務注冊時將會周期性維護一條注冊記錄,即機器地址和AppName的綁定關系; "調度中心" 從而可以動態感知每個AppName在線的機器列表;

      為保證系統"輕量級"并且降低學習部署成本,沒有采用Zookeeper作為注冊中心,采用DB方式進行任務注冊發現;

      六、版本更新日志

      6.1 版本 V1.1.x,新特性

      【于V1.1.x版本,XXL-JOB正式應用于我司,內部定制別名為 “Ferrari”,新接入應用推薦使用最新版本】

      • 1、簡單:支持通過Web頁面對任務進行CRUD操作,操作簡單,一分鐘上手;
      • 2、動態:支持動態修改任務狀態,動態暫停/恢復任務,即時生效;
      • 3、服務HA:任務信息持久化到mysql中,Job服務天然支持集群,保證服務HA;
      • 4、任務HA:某臺Job服務掛掉,任務會平滑分配給其他的某一臺存活服務,即使所有服務掛掉,重啟時或補償執行丟失任務;
      • 5、一個任務只會在其中一臺服務器上執行;
      • 6、任務串行執行;
      • 7、支持自定義參數;
      • 8、支持遠程任務執行終止;

      6.2 版本 V1.2.x,新特性

      • 1、支持任務分組;
      • 2、支持“本地任務”、“遠程任務”;
      • 3、底層通訊支持兩種方式,Servlet方式 + JETTY方式;
      • 4、支持“任務日志”;
      • 5、支持“串行執行”,并行執行;

        說明:V1.2版本將系統架構按功能拆分為:

      • 調度模塊(調度中心):負責管理調度信息,按照調度配置發出調度請求;
      • 執行模塊(執行器):負責接收調度請求并執行任務邏輯;
      • 通訊模塊:負責調度模塊和任務模塊之間的信息通訊;</pre>

        優點:

      • 解耦:任務模塊提供任務接口,調度模塊維護調度信息,業務相互獨立;
      • 高擴展性;
      • 穩定性;</pre> </li> </ul>

        6.3 版本 V1.3.0,新特性

        • 1、遺棄“本地任務”模式,推薦使用“遠程任務”,易于系統解耦,任務對應的JobHander統稱為“執行器”;
        • 2、遺棄“servlet”方式底層系統通訊,推薦使用JETTY方式,調度+回調雙向通訊,重構通訊邏輯;
        • 3、UI交互優化:左側菜單展開狀態優化,菜單項選中狀態優化,任務列表打開表格有壓縮優化;
        • 4、【重要】“執行器”細分為:BEAN、GLUE兩種開發模式,簡介見下文:

          “執行器” 模式簡介: - BEAN模式執行器:每個執行器都是Spring的一個Bean實例,XXL-JOB通過注解@JobHander識別和調度執行器; -GLUE模式執行器:每個執行器對應一段代碼,在線Web編輯和維護,動態編譯生效,執行器負責加載GLUE代碼和執行;

        6.4 版本 V1.3.1,新特性

        • 1、更新項目目錄結構:
          • /xxl-job-admin -------------------- 【調度中心】:負責管理調度信息,按照調度配置發出調度請求;
          • /xxl-job-core ----------------------- 公共依賴
          • /xxl-job-executor-example ------ 【執行器】:負責接收調度請求并執行任務邏輯;
          • /db ---------------------------------- 建表腳本
          • /doc --------------------------------- 用戶手冊
        • 2、在新的目錄結構上,升級了用戶手冊;
        • 3、優化了一些交互和UI;

        6.5 版本 V1.3.2,新特性

        • 1、調度邏輯進行事務包裹;
        • 2、執行器異步回調執行日志;
        • 3、【重要】在 “調度中心” 支持HA的基礎上,擴展執行器的Failover支持,支持配置多執行期地址;

        6.6 版本 V1.4.0 新特性

        • 1、任務依賴: 通過事件觸發方式實現, 任務執行成功并回調時會主動觸發一次子任務的調度, 多個子任務用逗號分隔;
        • 2、執行器底層實現代碼進行重度重構, 優化底層建表腳本;
        • 3、執行器中任務線程分組邏輯優化: 之前根據執行器JobHandler進行線程分組,當多個任務復用Jobhanlder會導致相互阻塞。現改為根據調度中心任務進行任務線程分組,任務與任務執行相互隔離;
        • 4、執行器調度通訊方案優化, 通過Hex + HC實現建議RPC通訊協議, 優化了通訊參數的維護和解析流程;
        • 5、調度中心, 新建/編輯任務, 界面屬性調整:
          • 5.1、任務新增/編輯界面中去除 "任務名JobName"屬性 ,該屬性改為系統自動生成: 該字段之前主要用于在 "調度中心" 唯一標示一個任務, 現實意義不大, 因此計劃淡化掉該字段,改為系統生成UUID,從而簡化任務新建的操作;
          • 5.2、任務新增/編輯界面中去除 "GLUE模式" 復選框位置調整, 改為貼近"JobHandler"輸入框右側;
          • 5.3、任務新增/編輯界面中去除 "報警閾值" 屬性;
          • 5.4、任務新增/編輯界面中去除 "子任務Key" 屬性, 每個任務全局任務Key可以從任務列表獲取, 當本任務執行結束且成功后, 將會根據子任務Key匹配子任務并主動觸發一次子任務執行;
        • 6、問題修復:
          • 6.1、執行器jetty關閉優化,解決一處可能導致jetty無法關閉的問題;
          • 6.2、執行器任務終止時,執行隊列回調優化,解決一處導致任務無法回調的問題;
          • 6.3、調度中心中列表分頁參數優化,解決一處因服務器限制post長度而引起的問題;
          • 6.4、執行器Jobhandler注解優化,解決一處因事務代理導致的容器無法加載JobHandler的問題;
          • 6.5、遠程調度優化,禁用retry策略,解決一處可能導致重復調用的問題;

        Tips: 歷史版本(V1.3.x)目前已經Release至穩定版本, 進入維護階段, 地址見分支 V1.3 。新特性將會在master分支持續更新。

        6.7 版本 V1.4.1 新特性

        • 1、項目成功推送maven中央倉庫, 中央倉庫地址以及依賴如下: <!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ --> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>${最新穩定版}</version> </dependency>
        • 2、為適配中央倉庫規則, 項目groupId從com.xxl改為com.xuxueli。
        • 3、系統版本不在維護在項目跟pom中,各個子模塊單獨配置版本配置,解決子模塊無法單獨編譯的問題;
        • 4、底層RPC通訊,傳輸數據的字節長度統計規則優化,可節省50%數據傳輸量;
        • 5、IJobHandler取消任務返回值,原通過返回值判斷執行狀態,邏輯改為:默認任務執行成功,僅在捕獲異常時認定任務執行失敗。
        • 6、系統公共彈框功能,插件化;
        • 7、底層表結構,表明統一大寫;
        • 8、調度中心,異常處理器JSON響應的ContentType修改,修復瀏覽器不識別的問題;

        6.8 版本 V1.4.2 新特性

        • 1、推送新版本 V1.4.2 至中央倉庫, 大版本 V1.4 進入維護階段;
        • 2、任務新增時,任務列表偏移問題修復;
        • 3、修復一處因bootstrap不支持模態框重疊而導致的樣式錯亂的問題, 在任務編輯時會出現該問題;
        • 4、調度超時和Handler匹配不到時,調度狀態優化;
        • 5、因catch異常,導致任務不可終止的問題,給出解決方案, 見文檔;

        6.9 版本 V1.5.0 特性

        • 1、任務注冊: 執行器會周期性自動注冊任務, 調度中心將會自動發現注冊的任務并觸發執行。
        • 2、"執行器" 新增參數 "AppName" : 是每個執行器集群的唯一標示AppName, 并周期性以AppName為對象進行自動注冊。
        • 3、調度中心新增欄目 "執行器管理" : 管理在線的執行器, 通過屬性AppName自動發現注冊的執行器。只有被管理的執行器才允許被使用;
        • 4、"任務組"屬性改為"執行器": 每個任務需要綁定指定的執行器, 調度地址通過綁定的執行器獲取;
        • 5、拋棄"任務機器"屬性: 通過任務綁定的執行器, 自動發現注冊的遠程執行器地址并觸發調度請求。
        • 6、"公共依賴"中新增DBGlueLoader,基于原生jdbc實現GLUE源碼的加載器,減少第三方依賴(mybatis,spring-orm等);精簡和優化執行器測配置(針對GLUE任務),降低上手難度;
        • 7、表結構調整,底層重構優化;
        • 8、"調度中心"自動注冊和發現,failover: 調度中心周期性自動注冊, 任務回調時可以感知在線的所有調度中心地址, 通過failover的方式進行任務回調,避免回調單點風險。

        6.10 版本 V1.5.1 特性

        • 1、底層代碼重構和邏輯優化,POM清理以及CleanCode;
        • 2、Servlet/JSP Spec設定為3.0/2.2
        • 3、Spring升級至3.2.17.RELEASE版本;
        • 4、Jetty升級版本至8.2.0.v20160908;
        • 5、已推送V1.5.0和V1.5.1至Maven中央倉庫;

        6.10 版本 V1.5.2 特性

        • 1、IP工具類獲取IP邏輯優化,IP靜態緩存;
        • 2、執行器、調度中心,均支持自定義注冊IP地址;解決機器多網卡時錯誤網卡注冊的情況;
        • 3、任務跨天執行時生成多份日志文件的問題修復;
        • 4、底層日志底層日志調整,非敏感日志level調整為debug;
        • 5、升級數據庫連接池c3p0版本;
        • 6、執行器log4j配置優化,去除無效屬性;
        • 7、底層代碼重構和邏輯優化以及CleanCode;
        • 8、GLUE依賴注入邏輯優化,支持別名注入;

        6.11 版本 V1.6.0 特性(CODING)

        • 1、通訊:hex 通訊調整為 http-rpc 模式;
        • 2、線程模型統一;
        • 3、執行器支持手動設置執行地址列表,提供開關切換使用注冊地址還是手動設置的地址;
        • 4、執行器路由規則:第一個、循環、隨機、順序故障(默認)轉移;

        TODO LIST

        • 1、支持腳本JOB(源碼或指定路徑), 即shell/python/php等, 日志實時輸出并支持在線監控;定制JobHandler實現;
        • 2、任務并行觸發處理規則:串行調度隊列(默認)、并行、忽略、覆蓋;
        • 3、任務權限管理;
        • 4、rolling日志,日志界面風格同glue任務編輯器;
        • 5、執行器,server啟動,注冊邏輯調整;
        • 6、通過listener或stop方法,容器銷毀時銷毀線程;Daemon方式有時不太理想;
        • 7、調度失敗重試機制;
        • 8、任務報表:總任務數、總調度數、調度成功比例;
 本文由用戶 JuniorWeddl 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!