天天看點

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

文章目錄

  • 1 概述
  • 2 特性
  • 3 架構設計
    • 3.1設計思想
    • 3.2 系統組成
    • 3.3架構圖
    • 3.4 高可用
      • 3.4.1 排程中心的高可用
      • 3.4.2 執行器的高可用
  • 4 搭建排程中心
    • 4.1 克隆源碼
    • 4.2 初始化 XXL-JOB 表結構
    • 修改配置檔案
    • 4.4 修改日志配置檔案
    • 4.5 IDEA 啟動排程中心
    • 4.6 編譯源碼
    • 4.7 指令行啟動排程中心
    • 4.8 搭建叢集
  • 5 搭建執行器
    • 5.1 引入依賴
    • 5.2 應用配置檔案
    • 5.3 XxlJobConfiguration
    • 5.4 DemoJob
    • 5.6 新增執行器
    • 5.7 建立任務

1 概述

XXL-JOB 是一個輕量級分布式任務排程平台,其核心設計目标是開發迅速、學習簡單、輕量級、易擴充。

從它登記的接入公司清單 ,可以看到拍拍貸、優信二手車、京東、哈啰出行等知名的網際網路公司正在使用中。是以,胖友們是可以放心大膽的在項目中使用。

2 特性

XXL-JOB 提供了 35 點特性清單

3 架構設計

3.1設計思想

  • 将排程行為抽象形成“排程中心”公共平台,而平台自身并不承擔業務邏輯,“排程中心”負責發起排程請求。
  • 将任務抽象成分散的

    JobHandler

    ,交由“執行器”統一管理,“執行器”負責接收排程請求并執行對應的 J

    obHandler

    中 業務邏輯。

是以,“排程”和“任務”兩部分可以互相解耦,提高系統整體穩定性和擴充性。

如果對分布式任務排程平台有一定了解的話,如果從排程系統的角度來看,可以分成兩類:

  • 中心化: 排程中心和執行器分離,排程中心統一排程,通知某個執行器處理任務。
  • 去中心化:排程中心和執行器一體化,自己排程自己執行處理任務。

如此可知 XXL-Job 屬于中心化的任務排程平台。目前采用這種方案的還有:

  • 鍊家的 kob
  • 美團的 Crane(暫未開源)

去中心化的任務排程平台,目前有:

  • Elastic Job
  • 唯品會的 Saturn
  • Quartz 基于資料庫的叢集方案
  • 淘寶的 TBSchedule(暫停更新,隻能使用阿裡雲 SchedulerX 服務)

3.2 系統組成

整個 XXL-JOB 系統,由排程中心和執行器兩個角色組成,分别處于不同的程序中。

排程中心:

  • 負責管理排程資訊,按照排程配置發出排程請求,自身不承擔業務代碼。
  • 排程系統與任務解耦,提高了系統可用性和穩定性,同時排程系統性能不再受限于任務子產品。
  • 支援可視化、簡單且動态的管理排程資訊,包括任務建立,更新,删除, GLUE 開發和任務報警等,所有上述操作都會實時生效。
  • 支援監控排程結果以及執行日志,支援執行器 Failover 。

執行器:

  • 負責接收排程請求并執行任務邏輯。任務子產品專注于任務的執行等操作,開發和維護更加簡單和高效。
  • 接收“排程中心”的執行請求、終止請求和日志請求等。

一般來說,XXL-JOB 執行器可以内嵌到應用服務裡。例如說,一個提供 Restful API 的 Spring Boot 項目中,引入 xxl-job-core 依賴,同時也作為一個 XXL-JOB 執行器。本質上,每次 Restful API 是請求任務,而每次任務排程是定時任務。(?)

3.3架構圖

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

注意,【】 中填寫排程中心和執行器;[] 中填寫元件名。

注意,左邊是排程中心,右邊是執行器。

【執行器】:[注冊線程] 根據配置的【排程中心】的位址,自動注冊到【排程中心】。

【排程中心】:達到任務觸發條件,【排程中心】下發任務給【執行器】。

【執行器】:基于 [任務線程池] 執行任務,并把執行結果放入 [記憶體隊列] 中、把 [執行日志] 寫入 Log 日志檔案中。

【執行器】:[回調線程] 消費 [記憶體隊列] 中的排程結果,主動上報給【排程中心】。

當使用者在【排程中心】檢視 [Rolling 任務日志],【排程中心】請求【執行器】,【執行器】讀取 Log 日志檔案并傳回日志詳情。

3.4 高可用

XXL-JOB 的高可用,需要考慮排程中心的高可用、以及執行器的高可用。

注意,雖然說 XXL-JOB 執行的是背景任務,即使挂掉,使用者的感覺度也比較低,但是考慮高可用是一種良好的習慣,在高性能之前請做好高可用。

3.4.1 排程中心的高可用

排程中心支援多節點部署,基于資料庫行鎖,保證觸發器的名稱和執行時間相同,則隻且僅有一個排程中心節點去下發任務給執行器。

核心代碼可見 XXL-JOB 的

JobScheduleHelper#start()

方法:

// JobScheduleHelper.java

// 獲得行鎖
conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection();
connAutoCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
preparedStatement = conn.prepareStatement(  "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" );
preparedStatement.execute();

// ...觸發任務排程

// 事務送出
conn.commit();
           

3.4.2 執行器的高可用

執行器支援多節點部署,通過排程中心選擇其中的執行器,下發任務來執行。

當任務”路由政策”選擇”故障轉移(FAILOVER)”時,當排程中心每次發起排程請求時,會按照順序對執行器發出心跳檢測請求,第一個檢測為存活狀态的執行器将會被標明并發送排程請求。

  1. 路由政策

    ——排程中心基于路由政策,選擇一個執行器節點下發任務,進而讓執行器執行任務。XXL-JOB 提供了如下路由政策保證任務排程高可用:

    • 忙碌轉移(BUSYOVER)政策:當排程中心每次發起排程請求時,會按照順序對執行器發出空閑檢測請求,第一個檢測為空閑狀态的執行器将會被標明并發送排程請求。具體代碼,見 ExecutorRouteFailover 類。
    • 故障轉移(FAILOVER)政策:當排程中心每次發起排程請求時,會按照順序對執行器發出心跳檢測請求,第一個檢測為存活狀态的執行器将會被標明并發送排程請求。具體代碼,見 ExecutorRouteFailover 類。
    還有第一個(FIRST)、LAST(最後一個)、輪詢(ROUND)、随機(RANDOM)、CONSISTENT_HASH(一緻性 HASH)、最不經常使用(LEAST_FREQUENTLY_USED)、最近最久未使用(LEAST_RECENTLY_USED)、分片廣播(SHARDING_BROADCAST)路由政策在 com.xxl.job.admin.core.route.strategy/ 包下
  2. 阻塞處理政策

    ——當排程過于密集時,執行器來不及處理時,則當執行器節點存在多個相同任務編号的任務未執行完成,則需要基于阻塞處理政策對任務進行取舍:

    • 單機串行(預設):排程請求進入單機執行器後,排程請求進入 FIFO 隊列并以串行方式運作。
    • 丢棄後續排程:排程請求進入單機執行器後,發現執行器存在運作的排程任務,本次請求将會被丢棄并标記為失敗。
    • 覆寫之前排程:排程請求進入單機執行器後,發現執行器存在運作的排程任務,将會終止運作中的排程任務并清空隊列,然後運作本地排程任務。
    具體可見 ExecutorBizImpl#run() 方法的代碼。

4 搭建排程中心

本小節,我們來搭建一個排程中心。XXL-JOB 暫未提供直接直接啟動的 jar 包,是以需要自己編譯源碼。

考慮到降低大家的學習成本,我們使用 IDEA 進行操作。

4.1 克隆源碼

用 IDEA ,從碼雲 https://gitee.com/xuxueli0323/xxl-job 克隆源碼,或者從 XXL-JOB Releases中克隆。

克隆完成後,耐心等待下載下傳完依賴。完成後,整體項目結構如下:

  • xxl-job-core

    子產品:XXL-JOB 核心。後續我們在編寫執行器時,會引入該子產品。
  • xxl-job-admin

    子產品:排程中心。
  • xxl-job-executor-samples

    子產品:提供了在 Spring、Spring Boot、JFinal、Nutz 等架構下的使用示例。

這裡,我們需要編譯的主要是

xxl-job-admin

子產品,即排程中心。

4.2 初始化 XXL-JOB 表結構

doc/db/tables_xxl_job.sql

位址,是 XXL-JOB 表結構的初始化腳本。我們需要在資料庫中執行該腳本,完成初始化 XXL-JOB 表結構。如下圖所示:XXL-JOB 表結構

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器
  • xxl_job_lock:任務排程鎖表;
  • xxl_job_group:執行器資訊表,維護任務執行器資訊;
  • xxl_job_info:排程擴充資訊表: 用于儲存 XXL-JOB 排程任務的擴充資訊,如任務分組、任務名、機器位址、執行器、執行入參和報警郵件等等;
  • xxl_job_log:排程日志表: 用于儲存 XXL-JOB 任務排程的曆史資訊,如排程結果、執行結果、排程入參、排程機器和執行器等等;
  • xxl_job_log_report:排程日志報表:使用者存儲 XXL-JOB 任務排程日志的報表,排程中心報表功能頁面會用到;
  • xxl_job_logglue:任務GLUE日志:用于儲存 GLUE 更新曆史,用于支援 GLUE 的版本回溯功能;
  • xxl_job_registry:執行器系統資料庫,維護線上的執行器和排程中心機器位址資訊;
  • xxl_job_user:系統使用者表;

自 XXL-JOB 2.1.0 Release 版本,去除對 Quartz 的依賴,是以我們就看不到 Quartz 相關的表哈。

修改配置檔案

打開

xxl-job-admin

子產品,修改

src/main/resources/application.properties

配置檔案。如下:

### web # Web 伺服器
server.port=8080
server.context-path=/xxl-job-admin

### actuator
management.context-path=/actuator
management.health.mail.enabled=false

### resources
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/

### freemarker
spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########

### mybatis
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml

### xxl-job, datasource 排程中心 JDBC 連結
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root_pwd
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.datasource.tomcat.max-wait=10000
spring.datasource.tomcat.max-active=30
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.tomcat.validation-interval=30000

### xxl-job email 報警郵箱
spring.mail.host=smtp.qq.com
spring.mail.port=25
[email protected]
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory

### xxl-job, access token 排程中心通訊TOKEN [選填]:非空時啟用;排程中心國際化配置 [選填]: 預設為空,表示中文; "en" 表示英文;
xxl.job.accessToken=

### xxl-job, i18n (default empty as chinese, "en" as english)
xxl.job.i18n=

## xxl-job, triggerpool max size 排程線程池最大線程配置
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100

### xxl-job, log retention days 排程中心日志表資料儲存天數 [必填]:過期日志自動清理;限制大于等于7時生效,否則, 如-1,關閉自動清理功能;
xxl.job.logretentiondays=30

           

可以看到 XXL-JOB 使用了 Spring Boot ,配置項比較多,說下必須要改的項:

  • server.port

    :XXL-JOB 排程中心的伺服器位址。可以根據自己的需要,修改該端口。
  • spring.datasource

    :XXL-JOB 排程中心的資料源位址,必須修改成自己準備提供給 XXL-JOB 的資料庫位址。
  • spring.mail

    :報警郵箱,生産環境下必須配置,不然定時任務執行報錯都不知道,簡直要命。😈 一般來說下,建議有時間的胖友,修改下 XXL-JOB 的源碼,把釘釘告警接入。
  • xxl.job.accessToken

    :排程中心通訊令牌,建議填寫。雖然說,内網一般很安全,但是以防萬一,并且又沒啥成本,直接給整上。

4.4 修改日志配置檔案

打開

xxl-job-admin

子產品,修改

src/main/resources/logback.xml

配置檔案。如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">

    <contextName>logback</contextName>
    <property name="log.path" value="/data/applogs/xxl-job/xxl-job-admin.log"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
            </pattern>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console"/>
        <appender-ref ref="file"/>
    </root>

</configuration>
           

預設情況下,日志輸出的位址是

/data/applogs/xxl-job/xxl-job-admin.log

。可以根據自己的需要,進行調整。

4.5 IDEA 啟動排程中心

在開始編譯源碼之前,我們先直接使用

XxlJobAdminApplication

類,運作啟動排程中心。這樣,避免我們後面編譯源碼,進行打包查出來的 jar 包,結果配置檔案不對的尴尬。

當看到如下日志,代表啟動成功:

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

啟動成功後,浏覽器 http://127.0.0.1:8080/xxl-job-admin 位址,并使用預設 “admin/123456” 進行登入。如果登入成功,說明我們已經配置正确啦。

4.6 編譯源碼

使用 Maven 打包指定

xxl-job-admin

子產品,打包完成後,在

xxl-job-admin/target/xxl-job-admin-2.1.2-SNAPSHOT.jar

位址下,就是我們要啟動的 XXL-JOB 排程中心的 jar 包。

4.7 指令行啟動排程中心

# 啟動排程中心
$ jar -jar xxl-job-admin-2.1.2-SNAPSHOT.jar
           

啟動成功後,浏覽器 http://127.0.0.1:8080/xxl-job-admin 位址,并使用預設 “admin/123456” 進行登入。如果登入成功,說明我們已經配置正确啦。

另外,啟動完成之後,記得右上角,修改下管理者的密碼。

4.8 搭建叢集

在生産環境下,一定要部署 XXL-JOB 排程中心的叢集,提升排程系統容災和可用性。

排程中心叢集部署時,幾點要求和建議:

  • DB 配置保持一緻;
  • 叢集機器時鐘保持一緻(單機叢集忽視);
  • 推薦通過 Nginx 為排程中心叢集做負載均衡,配置設定域名。排程中心通路、執行器回調配置、調用 API 服務等操作均通過該域名進行。

另外,如果胖友想要使用 Docker 鏡像方式搭建排程中心,可以自行參看 XXL-JOB 的官方文檔。

5 搭建執行器

5.1 引入依賴

建立一個springboot項目,在

pom.xml

檔案中,引入相關依賴。注意這裡的依賴版本要與排程中心的版本一緻!!

<!-- XXL-JOB 相關依賴 -->
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>2.3.1</version>
        </dependency>
           

5.2 應用配置檔案

在 application.yml 中,添加 Quartz 的配置,如下:

server:
  port: 9090 #指定一個端口,避免和 XXL-JOB 排程中心的端口沖突。僅僅測試之用

# xxl-job
xxl:
  job:
    admin:
      addresses: http://xxxx.1:8080/xxl-job-admin # 排程中心部署跟位址(不能使用127.0.0.1) [選填]:如排程中心叢集部署存在多個位址則用逗号分隔。執行器将會使用該位址進行"執行器心跳注冊"和"任務結果回調";為空則關閉自動注冊;
    executor:
      appname: task-xxl-job # 執行器 AppName [選填]:執行器心跳注冊分組依據;為空則關閉自動注冊
      ip: # 執行器IP [選填]:預設為空表示自動擷取IP,多網卡時可手動設定指定IP,該IP不會綁定Host僅作為通訊實用;位址資訊用于 "執行器注冊" 和 "排程中心請求并觸發任務";
      port: 6666 # ### 執行器端口号 [選填]:小于等于0則自動擷取;預設端口為9999,單機部署多個執行器時,注意要配置不同執行器端口;
      logpath: /logs # 執行器運作日志檔案存儲磁盤路徑 [選填] :需要對該路徑擁有讀寫權限;為空則使用預設路徑;
      logretentiondays: 30 # 執行器日志檔案儲存天數 [選填] : 過期日志自動清理, 限制值大于等于3時生效; 否則, 如-1, 關閉自動清理功能;
    accessToken:  # 執行器通訊TOKEN [選填]:非空時啟用;
           

5.3 XxlJobConfiguration

Application

同級目錄下建立

config

包,并建立 DataSourceConfiguration 類,配置 XXL-JOB 執行器。代碼如下:

@Configuration
public class XxlJobConfiguration {

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;
    @Value("${xxl.job.executor.appname}")
    private String appName;
    @Value("${xxl.job.executor.ip}")
    private String ip;
    @Value("${xxl.job.executor.port}")
    private int port;
    @Value("${xxl.job.accessToken}")
    private String accessToken;
    @Value("${xxl.job.executor.logpath}")
    private String logPath;
    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;

    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        // 建立 XxlJobSpringExecutor 執行器
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appName);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        // 傳回
        return xxlJobSpringExecutor;
    }

}
           

xxlJobExecutor()

方法,建立了 Spring 容器下的 XXL-JOB 執行器 Bean 對象。要注意,方法上添加了的

@Bean

注解,配置了啟動和銷毀方法。

5.4 DemoJob

Application

同級目錄下建立

job

包,并建立 DemoJob 類,示例定時任務類。代碼如下:

在xxl-job 2.2版本之前可以使用

@JobHandler

并繼承

IJobHandler

@Component
@JobHandler("demoJob")
public class DemoJob extends IJobHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private final AtomicInteger counts = new AtomicInteger();

    @Override
    public ReturnT<String> execute(String param) throws Exception {
        // 列印日志
        logger.info("[execute][定時第 ({}) 次執行]", counts.incrementAndGet());
        // 傳回執行成功
        return ReturnT.SUCCESS;
    }

}
           

在xxl-job 2.2版本之後,使用

@XxlJob

替代了原方法

@Component
public class DemoJob {
    private Logger logger = LoggerFactory.getLogger(getClass());
//
    private final AtomicInteger counts = new AtomicInteger();

    @XxlJob("demoJobHandler")
    public ReturnT<String> demoJobHandler(String param) throws Exception {
        logger.info("[execute][定時第 ({}) 次執行]", counts.incrementAndGet());
        return ReturnT.SUCCESS;
    }
}
           

此時運作項目并不會成功,因為我們還需要在排程中心先注冊執行器

5.6 新增執行器

浏覽器打開 http://127.0.0.1:8080/xxl-job-admin/jobgroup 位址,即「執行器管理」菜單。如下圖:

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

新增執行器:

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

xxl-job 2.3.1

版本中,使用自動注冊的機器位址不會加上

http://

而會導緻之後調用任務失敗,這裡推薦手動配置一下

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

5.7 建立任務

浏覽器打開 http://127.0.0.1:8080/xxl-job-admin/jobinfo 位址,即「任務管理」菜單。如下圖:

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

點選最右邊的「新增」按鈕,彈出「新增」界面。如下圖:

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

填寫完記得切換執行器

XXL-JOB 極簡入門1 概述2 特性3 架構設計4 搭建排程中心5 搭建執行器

點選 “demoJob” 任務的「操作」按鈕,選擇「啟動」,确認後,該 “demoJob” 任務的狀态就變成了 RUNNING 。

此時,我們打開執行器的 IDE 界面,可以看到 DemoJob 已經在每秒鐘執行一次了。