xxl-job 分布式任務調度框架


spring傳統的定時任務@Scheduled,但是這樣存在這一些問題 :

  • 做集群任務的重復執行問題;(某個微服務要做集群,每一個微服務下都有當前的任務,這是應該如何解決重復執行的問題呢?可以使用分布式鎖,但是比較麻煩)

  • cron表達式定義在代碼之中,修改不方便;

  • 定時任務失敗了,無法重試也沒有統計;

  • 如果任務量過大,不能有效的分片執行;

解決這些問題的方案為:xxl-job 分布式任務調度框架

一、分布式任務調度

 1、什么是分布式任務調度

當前軟件的架構已經開始向分布式架構轉變,將單體結構拆分為若干服務,服務之間通過網絡交互來完成業務處理。在分布式架構下,一個服務往往會部署多個實例來運行我們的業務,如果在這種分布式系統環境下運行任務調度,我們稱之為分布式任務調度

 將單體應用拆分成多個微服務,為了提升系統並發可用性,我們做集群,

將任務調度程序分布式構建,這樣就可以具有分布式系統的特點,並且提高任務的調度處理能力:

(1)、並行任務調度

並行任務調度實現靠多線程,如果有大量任務需要調度,此時光靠多線程就會有瓶頸了,因為一台計算機CPU的處理能力是有限的。

如果將任務調度程序分布式部署,每個結點還可以部署為集群,這樣就可以讓多台計算機共同去完成任務調度,我們可以將任務分割為若干個分片,由不同的實例並行執行,來提高任務調度的處理效率。

(2)、高可用

若某一個實例宕機,不影響其他實例來執行任務。

(3)、彈性擴容

當集群中增加實例就可以提高並執行任務的處理效率。

(4)、任務管理與監測

對系統中存在的所有定時任務進行統一的管理及監測。讓開發人員及運維人員能夠時刻了解任務執行情況,從而做出快速的應急處理響應。

分布式任務調度面臨的問題:

當任務調度以集群方式部署,同一個任務調度可能會執行多次,例如:電商系統定期發放優惠券,就可能重復發放優惠券,對公司造成損失,信用卡還款提醒就會重復執行多次,給用戶造成煩惱,所以我們需要控制相同的任務在多個運行實例上只執行一次。常見解決方案:

  • 分布式鎖,多個實例在任務執行前首先需要獲取鎖,如果獲取失敗那么就證明有其他服務已經在運行,如果獲取成功那么證明沒有服務在運行定時任務,那么就可以執行

  • ZooKeeper選舉,利用ZooKeeper對Leader實例執行定時任務,執行定時任務的時候判斷自己是否是Leader,如果不是則不執行,如果是則執行業務邏輯,這樣也能達到目的。

2、xxl-Job簡介

這是美團公司一個程序員開源的框架

針對分布式任務調度的需求,市場上出現了很多的產品:

1)、TBSchedule:淘寶推出的一款非常優秀的高性能分布式調度框架,目前被應用於阿里、京東、支付寶、國美等很多互聯網企業的流程調度系統中。但是已經多年未更新,文檔缺失嚴重,缺少維護。

2)、XXL-Job:大眾點評的分布式任務調度平台,是一個輕量級分布式任務調度平台, 其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。現已開放源代碼並接入多家公司線上產品線,開箱即用。

3)、Elastic-job:當當網借鑒TBSchedule並基於quartz 二次開發的彈性分布式任務調度系統,功能豐富強大,采用zookeeper實現分布式協調,具有任務高可用以及分片功能。

4)、Saturn: 唯品會開源的一個分布式任務調度平台,基於Elastic-job,可以全域統一配置,統一監 控,具有任務高可用以及分片功能。

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

源碼地址:https://gitee.com/xuxueli0323/xxl-job

文檔地址:https://www.xuxueli.com/xxl-job/

 

特性

  • 簡單靈活 提供Web頁面對任務進行管理,管理系統支持用戶管理、權限控制; 支持容器部署; 支持通過通用HTTP提供跨平台任務調度;

  • 豐富的任務管理功能 支持頁面對任務CRUD操作; 支持在頁面編寫腳本任務、命令行任務、Java代碼任務並執行; 支持任務級聯編排,父任務執行結束后觸發子任務執行; 支持設置指定任務執行節點路由策略,包括輪詢、隨機、廣播、故障轉移、忙碌轉移等; 支持Cron方式、任務依賴、調度中心API接口方式觸發任務執行

  • 高性能 任務調度流程全異步化設計實現,如異步調度、異步運行、異步回調等,有效對密集調度進行流量削峰;

  • 高可用 任務調度中心、任務執行節點均 集群部署,支持動態擴展、故障轉移 支持任務配置路由故障轉移策略,執行器節點不可用是自動轉移到其他節點執行 支持任務超時控制、失敗重試配置 支持任務處理阻塞策略:調度當任務執行節點忙碌時來不及執行任務的處理策略,包括:串行、拋棄、覆蓋策略

  • 易於監控運維 支持設置任務失敗郵件告警,預留接口支持短信、釘釘告警; 支持實時查看任務執行運行數據統計圖表、任務進度監控數據、任務完整執行日志;

3、XXL-Job-環境搭建

(1)、調度中心環境要求

  • Maven3+

  • Jdk1.8+

  • Mysql5.7+

(2)、源碼倉庫地址

源碼倉庫地址 Release Download
https://github.com/xuxueli/xxl-job Download
http://gitee.com/xuxueli0323/xxl-job Download

我們訪問馬雲上面的地址去下載源碼,我們下載2.3.0版本。

也可以使用資料文件夾中的源碼,目錄結構如下:

使用idea打開

xxl-job-admin為調度中心,一會我們會部署這個調度中心。

xxl-job-core為核心源碼,如果我們想要在項目中使用xxl-job,必須導入這個核心依賴。xxl-job-executor-samples是一些案例,我們會重點分析xxl-job-executor-sample-springboot這個springboot集成樣例。

(3)、初始化“調度數據庫”

請下載項目源碼並解壓,獲取 “調度數據庫初始化SQL腳本” 並執行即可。

位置:/xxl-job/doc/db/tables_xxl_job.sql 共8張表

- xxl_job_lock:任務調度鎖表;
- xxl_job_group:執行器信息表,維護任務執行器信息;
- xxl_job_info:調度擴展信息表: 用於保存XXL-JOB調度任務的擴展信息,如任務分組、任務名、機器地址、執行器、執行入參和報警郵件等等;
- xxl_job_log:調度日志表: 用於保存XXL-JOB任務調度的歷史信息,如調度結果、執行結果、調度入參、調度機器和執行器等等;
- xxl_job_logglue:任務GLUE日志:用於保存GLUE更新歷史,用於支持GLUE的版本回溯功能;
- xxl_job_registry:執行器注冊表,維護在線的執行器和調度中心機器地址信息;
- xxl_job_user:系統用戶表;

調度中心支持集群部署,集群情況下各節點務必連接同一個mysql實例;

如果mysql做主從,調度中心集群節點務必強制走主庫;

4、配置部署“調度中心”

調度中心項目:xxl-job-admin

作用:統一管理任務調度平台上調度任務,負責觸發調度執行,並且提供任務管理平台。

步驟一:調度中心配置

修改mysql驅動的版本

調度中心配置文件地址:/xxl-job/xxl-job-admin/src/main/resources/application.properties

數據庫的連接信息修改為自己的數據庫,修改端口,避免沖突。

### web
server.port=8989
server.servlet.context-path=/xxl-job-admin

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

### resources
spring.mvc.servlet.load-on-startup=0
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
#mybatis.type-aliases-package=com.xxl.job.admin.core.model

### xxl-job, datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

### datasource-pool
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=HikariCP
spring.datasource.hikari.max-lifetime=900000
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.validation-timeout=1000

### xxl-job, email
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.from=xxx@qq.com
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
xxl.job.accessToken=

### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
xxl.job.i18n=zh_CN

## xxl-job, triggerpool max size
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100

### xxl-job, log retention days
xxl.job.logretentiondays=30

啟動調度中心,瀏覽器訪問:http://localhost:8989/xxl-job-admin/toLogin,

默認登錄賬號 “admin/123456”, 登錄后運行界面如下圖所示。

說明調度中心安裝完畢。

由於調度中心是一個服務,我們可以將xxl-job-admin打成一個jar包,然后通過java -jar xxl-job-admin-2.3.0.jar來啟動。還可以創建startup.bat文件,內容為java -jar xxl-job-admin-2.3.0.jar,這樣,雙擊該文件就可以啟動。

5、配置部署調度中心-docker安裝

(1)、創建mysql容器,初始化xxl-job的SQL腳本

docker run -p 3306:3306 --name mysql57 \
-v /opt/mysql/conf:/etc/mysql \
-v /opt/mysql/logs:/var/log/mysql \
-v /opt/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

 獲取 “調度數據庫初始化SQL腳本” 並執行。

 (2)、拉取鏡像

docker pull xuxueli/xxl-job-admin:2.3.0

(3)、創建容器

docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://172.17.0.2:3306/xxl_job?Unicode=true&characterEncoding=UTF-8 \
--spring.datasource.username=root \
--spring.datasource.password=123456" \
-p 8989:8080 -v /tmp:/data/applogs \
--name xxl-job-admin --restart=always  -d xuxueli/xxl-job-admin:2.3.0

注意:172.17.0.2是mysql在bridge網段的IP。mysql和xxl-job在同一網段。

去掉\改成一行執行

docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://172.17.0.2:3306/xxl_job?Unicode=true&characterEncoding=UTF-8 --spring.datasource.username=root --spring.datasource.password=123456" -p 8989:8080 -v /tmp:/data/applogs --name xxl-job-admin --restart=always  -d xuxueli/xxl-job-admin:2.3.0

如果是雲服務器,則在安全組中放開8989端口。

瀏覽器訪問:http://IP:8989/xxl-job-admin/toLogin,進入如下所示頁面:

默認登錄賬號 “admin/123456”, 登錄后運行界面如下圖所示。

說明調度中心安裝完畢。

二、xxl-job入門案例

 1、創建執行器並注冊到調度中心

 點擊執行器管理,發現已經創建好了一個執行器:

 

我們根據項目名xxl-job-demo添加一個執行器

如果選擇“自動注冊”,那么“機器地址”中將禁止輸入。

注意:AppName輸入框中的值與執行器xxl-job-demo中配置文件的名稱(xxl.job.executor.appname)保持一致,而不是跟spring.application.name保持一直,否則會出現執行器無法注冊的情況

名稱輸入框任意填寫。

xxl:
  job:
    executor:
 appname: xxl-job-demo

啟動執行器即xxl-job-demo項目,刷新執行器管理頁面,效果如下:

 發現有一個節點已經注冊進來了,執行器注冊成功。

執行器其實是根據任務進行分類。創建任務的時候必須指定在哪一個執行器下創建。

2、創建定時任務並綁定執行器

點擊任務管理,發現已經創建了一個任務。

點擊編輯,修改cron表達式為:0/1 * * * * ? *,表示每秒運行一次

我們自己創建一個任務

注意:demoJobHandler要與@XxlJob注解中的值一致。

點擊保存,如下所示

3、創建一個springboot工程並引入依賴

<!-- 繼承Spring boot工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--xxl-job-->
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>

注意:這里的版本與你xxl-job-admin的版本保持一致,否則可能出現執行失敗的情況。

4、編寫application.yml配置文件

server:
  port: 8881

xxl:
  job:
    admin:
      addresses: http://127.0.0.1:8989/xxl-job-admin
    executor:
      appname: xxl-job-demo
      port: 9898

定義執行器的名稱xxl-job-demo和端口9898,執行器xxl-job-demo中配置文件的名稱要與xxl-job-admin中AppName輸入框中的值保持一致。

執行器端口可以自定義。如果有多個實例,則端口不要重復。

注意:調度中心要能訪問本地才行,不能把調度中心放到雲服務器,把該demo放到本地電腦。

XXL-JOB執行器的相關配置項的意義:

(1)、xxl.job.admin.addresses
調度中心的部署地址。若調度中心采用集群部署,存在多個地址,則用逗號分隔。執行器將會使用該地址進行”執行器心跳注冊”和”任務結果回調”。

(2)、xxl.job.executor.appname
執行器的應用名稱,它是執行器心跳注冊的分組依據。

(3)、xxl.job.executor.ip
執行器的IP地址,用於”調度中心請求並觸發任務”和”執行器注冊”。執行器IP默認為空,表示自動獲取IP。多網卡時可手動設置指定IP,手動設置IP時將會綁定Host。

(4)、xxl.job.executor.port
執行器的端口號,默認值為9999。單機部署多個執行器時,注意要配置不同的執行器端口。

(5)、xxl.job.accessToken
執行器的通信令牌,非空時啟用

(6)、xxl.job.executor.logpath
執行器輸出的日志文件的存儲路徑,需要擁有該路徑的讀寫權限。

(7)、xxl.job.executor.logretentiondays
執行器日志文件的定期清理功能,指定日志保存天數,日志文件過期自動刪除。限制至少保存3天,否則功能不生效。

更多配置時如下:

xxl.job.admin.addresses=http://127.0.0.1:8989/xxl-job-admin
xxl.job.executor.appname=xxl-job-cmdptcp
xxl.job.executor.port=9897

xxl.job.executor.ip=
xxl.job.executor.address=
xxl.job.accessToken=default_token
xxl.job.executor.logpath=/data/xxl-job/log
xxl.job.executor.logretentiondays=10

 

5、編寫配置類

import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * xxl-job config
 *
 * @author xuxueli 2017-04-28
 */
@Configuration
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.executor.appname}")
    private String appname;

    @Value("${xxl.job.executor.port}")
    private int port;
    
    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setPort(port);
        return xxlJobSpringExecutor;
    }
}

告訴spring調度中心是哪一個,執行器是哪一個,執行器端口是什么。

更多配置時如下:

@Configuration
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.executor.appname}")
    private String appname;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.executor.address}")
    private String address;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @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() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        return xxlJobSpringExecutor;
    }
}

 

6、編寫啟動類

@SpringBootApplication
public class XxlJobApplication {
    public static void main(String[] args) {
        SpringApplication.run(XxlJobApplication.class,args);
    }
}

7、創建任務

import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;

@Component public class HelloJob {
    
    @XxlJob("demoJobHandler")
    public void helloJob(){
        System.out.println("簡單任務執行了。。。。");

    }
}

8、測試單節點

(1)、啟動項目

(2)、啟動任務

 

目前任務是停止狀態,點擊操作,再選擇啟動,再點擊確定,此時狀態變為running

此時控制台打印如下:

簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。

查詢日志:

三、任務詳解

1、執行器

執行器:任務綁定執行器執行器注冊到調度中心成功之后,任務觸發調度時將會自動發現注冊成功的執行器, 實現任務自動發現功能,才能執行我們的任務

另一方面也可以方便的進行任務分組。每個任務必須綁定一個執行器;

以下是執行器的屬性說明:

屬性名稱 說明
AppName 是每個執行器集群的唯一標示AppName, 執行器會周期性以AppName為對象進行自動注冊。可通過該配置自動發現注冊成功的執行器, 供任務調度時使用;
名稱 執行器的名稱, 因為AppName限制字母數字等組成,可讀性不強, 名稱為了提高執行器的可讀性;
排序 執行器的排序, 系統中需要執行器的地方,如任務新增, 將會按照該排序讀取可用的執行器列表;
注冊方式 調度中心獲取執行器地址的方式;
機器地址 注冊方式為"手動錄入"時有效,支持人工維護執行器的地址信息;

自動注冊和手動注冊的區別和配置

2、基礎配置

基礎配置

  • 執行器:每個任務必須綁定一個執行器, 方便給任務進行分組;

  • 任務描述:任務的描述信息,便於任務管理;

  • 負責人:任務的負責人;

  • 報警郵件:任務調度失敗時郵件通知的郵箱地址,支持配置多郵箱地址,配置多個郵箱地址時用逗號分隔;

調度配置

  • 調度類型:

    • 無:該類型不會主動觸發調度;

    • CRON:該類型將會通過CRON,觸發任務調度;

    • 固定速度:該類型將會以固定速度,觸發任務調度;按照固定的間隔時間,周期性觸發;

任務配置

  • 運行模式:

BEAN模式:任務以JobHandler方式維護在執行器端(java代碼使用Bean模式);需要結合 "JobHandler" 屬性匹配執行器中任務;

  • JobHandler:運行模式為 "BEAN模式" 時生效,對應執行器中新開發的JobHandler類“@JobHandler”注解自定義的value值;

  • 執行參數:任務執行所需的參數;

注意:中間用英文逗號分隔。

此時執行,參數自定填寫到“任務參數”

高級配置:主要爭對集群模式。

阻塞處理策略

阻塞處理策略:調度過於密集(任務量特別大)執行器來不及處理時的處理策略;

  • 單機串行(默認):調度請求進入單機執行器后,調度請求進入FIFO(First Input First Output)隊列並以串行方式運行;

  • 丟棄后續調度:調度請求進入單機執行器后,發現執行器存在運行的調度任務,本次請求將會被丟棄並標記為失敗;

  • 覆蓋之前調度:調度請求進入單機執行器后,發現執行器存在運行的調度任務,將會終止運行中的調度任務並清空隊列,然后運行本地調度任務;

路由策略

當執行器集群部署時,提供豐富的路由策略,包括;

  • FIRST(第一個):固定選擇第一個機器;

  • LAST(最后一個):固定選擇最后一個機器;

  • ROUND(輪詢)

  • RANDOM(隨機):隨機選擇在線的機器;

  • CONSISTENT_HASH(一致性HASH):每個任務按照Hash算法固定選擇某一台機器,且所有任務均勻散列在不同機器上。

  • LEAST_FREQUENTLY_USED(最不經常使用):使用頻率最低的機器優先被選舉;

  • LEAST_RECENTLY_USED(最近最久未使用):最久未使用的機器優先被選舉;

  • FAILOVER(故障轉移):按照順序依次進行心跳檢測,第一個心跳檢測成功的機器選定為目標執行器並發起調度;

  • BUSYOVER(忙碌轉移):按照順序依次進行空閑檢測,第一個空閑檢測成功的機器選定為目標執行器並發起調度;

  • SHARDING_BROADCAST(分片廣播):廣播觸發對應集群中所有機器執行一次任務,同時系統自動傳遞分片參數;可根據分片參數開發分片任務;

3、路由策略(輪詢)

 (1)、修改路由策略為輪詢

 

(2)、啟動多個服務

 修改配置

server:
  port: ${port:8881}

xxl:
  job:
    admin:
      addresses: http://127.0.0.1:8989/xxl-job-admin
    executor:
      appname: xxl-job-demo
      port: ${executor.port:9898}

修改任務代碼

@Component
public class HelloJob {
    @Value("${server.port}")
    private String port;
    
    @XxlJob("demoJobHandler")
    public void helloJob(){
        System.out.println("簡單任務執行了。。。。" + port);

    }
}

啟動

點擊復制

啟動這兩個服務器,這兩個服務連接同一個執行器,並執行同一個任務。

發現已經有兩個節點注冊成功了。下面啟動任務,發現每個微服務輪詢的去執行任務。

4、路由策略(分片廣播)

分片邏輯

支付寶花唄每月10都會通知用戶還款,用戶量很大,有可能上億,任務量特別的大,如果使用輪詢的話,任務執行的效率肯定是不高的。那在同一個時間點執行大量的任務,通常情況下,我們肯定要做集群,我們給每一台服務器分配任務:實例1執行任務123,實例2執行任務456,實例3執行任務789。他們同時執行任務,這樣就分攤了各個實例的壓力, 

那在xxl-job中是如何做的呢?通過取模的方式將任務分配到各個分片執行。

執行器集群部署時,任務路由策略選擇”分片廣播”情況下,一次任務調度將會廣播觸發對應集群中所有執行器執行一次任務。

路由策略(分片廣播)-案例

需求:讓兩個節點同時執行10000個任務,每個節點分別執行5000個任務

 (1)、創建分片執行器

 (2)、創建任務,路由策略為分片廣播

(3)、分片廣播代碼

由於執行器的appname變了,故要修改配置文件

server:
  port: ${port:8881}

xxl:
  job:
    admin:
      addresses: http://127.0.0.1:8989/xxl-job-admin
    executor:
      appname: xxl-job-sharding-executor
      port: ${executor.port:9898}

分片參數

index:當前分片序號(從0開始),執行器集群列表中當前執行器的序號;

total:總分片數,執行器集群的總機器數量;

import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class HelloJob {
    @Value("${server.port}")
    private String port;

    @XxlJob("demoJobHandler")
    public void helloJob(){
        System.out.println("簡單任務執行了。。。。" + port);
    }
    @XxlJob("shardingJobHandler")
    public void shardingJobHandler() {
        // 獲取分片參數
        int shardIndex = XxlJobHelper.getShardIndex(); // 當前分片序號,從0開始
        int shardTotal = XxlJobHelper.getShardTotal(); // 總分片數
        // 業務邏輯
        List<Integer> list = getList();
        for (Integer integer : list) {
            // 將任務的數值模總分片數
            if (integer % shardTotal == shardIndex) {
                System.out.println("當前第"+shardIndex+"分片執行了,任務項為:"+integer);
            }
        }
    }

    public List<Integer> getList(){
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            list.add(i);
        }
        return list;
    }
}

(4)、測試

 啟動多個服務測試,一次執行可以執行多個任務

此時執行器注冊成功,如下所示:

我們啟動任務,只執行一次

XxlJobApplication-1服務的控制台打印如下:

.....
當前第0分片執行了,任務項為:9978
當前第0分片執行了,任務項為:9980
當前第0分片執行了,任務項為:9982
當前第0分片執行了,任務項為:9984
當前第0分片執行了,任務項為:9986
當前第0分片執行了,任務項為:9988
當前第0分片執行了,任務項為:9990
當前第0分片執行了,任務項為:9992
當前第0分片執行了,任務項為:9994
當前第0分片執行了,任務項為:9996
當前第0分片執行了,任務項為:9998

XxlJobApplication-2服務的控制台打印如下:

.......
當前第1分片執行了,任務項為:9979
當前第1分片執行了,任務項為:9981
當前第1分片執行了,任務項為:9983
當前第1分片執行了,任務項為:9985
當前第1分片執行了,任務項為:9987
當前第1分片執行了,任務項為:9989
當前第1分片執行了,任務項為:9991
當前第1分片執行了,任務項為:9993
當前第1分片執行了,任務項為:9995
當前第1分片執行了,任務項為:9997
當前第1分片執行了,任務項為:9999

現在只執行了一次任務,每個服務執行了5000次任務,如果任務量特別大的時候,我們可以通過分片廣播去緩解各個服務的壓力,

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM