分布式定時任務


任務調度場景

概述

在平時的業務場景中,經常有一些場景需要使用定時任務。

時間驅動的場景

  • 某個時間點發送優惠券,發送短信等等
  • 生成報表
  • 爬蟲(定點爬取某排行榜信息)

批量處理數據

批量統計上個月的賬單,統計上個月銷售數據等等。

固定頻率的場景

每隔 5 分鍾需要執行一次。

為什么需要任務調度平台

在 Java 中,傳統的定時任務實現方案,比如 Timer,Quartz 等,缺點:不支持集群、不支持統計、沒有管理平台、沒有失敗報警、沒有監控等等,分布式的架構中,有一些場景需要分布式任務調度,同一個服務多個實例的任務存在互斥時,需要統一的調度,任務調度需要支持高可用、監控、故障告警。需要統一管理和追蹤各個服務節點任務調度的結果,需要記錄保存任務屬性信息等。

什么是分布式任務調度

任務調度是指基於給定的時間點,給定的時間間隔或者給定執行次數自動的執行任務。任務調度是是操作系統的重要組成部分,而對於實時的操作系統,任務調度直接影響着操作系統的實時性能。任務調度涉及到多線程並發、運行時間規則定制及解析、線程池的維護等諸多方面的工作。

任務調度框架

非分布式

在單一服務器當中,創建定時任務,@Scheduled

分布式

把分散的,可靠性差的計划任務納入統一的平台,並實現集群管理調度和分布式部署的一種定時任務的管理方式,叫做分布式定時任務

Quartz

  • 先驅者
  • 無圖形化界面
  • 接口不人性化

Elasticjob

  • 基於 Quartz
  • elastic-job 是由當當網基於 Quartz 二次開發之后的分布式調度解決方案
  • 依賴很多中間件 zk

xxl-job

  • 美團點評里面開發者開發出來的

SchedulerX

  • 阿里雲出的一個框架
  • 商用產品

PowerJob

  • 個人

對比:

image-20211005103645171

@Scheduled

創建工程:

image-20211005215756861

image-20211005215830979

使用 @Scheduled 添加注解創建 JobTest.java:

/**
 * @author BNTang
 * @version 1.0
 * @project distributed-TimedTask
 * @description
 * @since Created in 2021/10/5 005 22:00
 **/
@Slf4j
@Component
@EnableScheduling
public class JobTest {
    @Scheduled(fixedDelayString = "3000", initialDelay = 5000)
    public void work() throws InterruptedException {
        log.info("work任務開始!");
        Thread.sleep(5000);
    }
}

啟動之后運行效果如下圖所示:

image-20211005221057668

  • @EnableScheduling:是否要開啟 Scheduled 也可以加在啟動類上,整個項目生效,@Scheduled 注解中屬性的取值的含義,fixedDelayString、fixedDelay 代表固定延時,要等上一次任務結束時,下一次才開始計時,initialDelay 代表延遲啟動。

修改一下 JobTest.java 的內容這里還需要在介紹一個 @Scheduled 注解當中的另外一個屬性代碼如下:

/**
 * @author BNTang
 * @version 1.0
 * @project distributed-TimedTask
 * @description
 * @since Created in 2021/10/5 005 22:00
 **/
@Slf4j
@Component
@EnableScheduling
public class JobTest {
    @Scheduled(fixedRateString = "3000", initialDelay = 5000)
    public void show() throws InterruptedException {
        log.info("show任務開始!");
        Thread.sleep(5000);
    }
}

啟動之后運行效果如下圖所示:

image-20211005221525367

  • fixedRateString 代表的是等上一個任務結束之后,立馬執行下一個任務,不會在等 3 秒,每隔 3 秒執行一次,程序耗時是 5 秒,由於是單線程,要等上一次方法執行完后,立馬執行下一次。

異步任務調度

開啟異步調度

image-20211005221916955

創建異步任務

image-20211006100458713

/**
 * @author BNTang
 * @version 1.0
 * @project distributed-TimedTask
 * @description
 * @since Created in 2021/10/5 005 22:20
 **/
@Slf4j
@Component
public class MyTask {
    @Async
    public void doTask() throws InterruptedException {
        log.info("doTask任務開始!");
        Thread.sleep(5000);
        log.info("doTask任務結束!");
    }
}

調用異步任務

image-20211006100811088

/**
 * @author BNTang
 * @version 1.0
 * @project distributed-TimedTask
 * @description
 * @since Created in 2021/10/5 005 22:00
 **/
@Slf4j
@Component
@EnableScheduling
public class JobTest {

    @Resource
    private MyTask myTask;

    @Scheduled(fixedRateString = "3000", initialDelay = 5000)
    public void show() throws InterruptedException {
        log.info("show任務開始!");
        this.myTask.doTask();
        log.info("show任務結束!");
    }
}

啟動之后運行效果如下圖所示:

image-20211006100910131

開啟多線程執行

修改 JobTest.java:

/**
 * @author BNTang
 * @version 1.0
 * @project distributed-TimedTask
 * @description
 * @since Created in 2021/10/5 005 22:00
 **/
@Slf4j
@Component
@EnableScheduling
public class JobTest {

    @Scheduled(fixedRateString = "3000")
    public void work() throws InterruptedException {
        log.info("work任務開始!");
        Thread.sleep(5000);
        log.info("work任務結束!");
    }

    @Scheduled(fixedRateString = "3000")
    public void show() throws InterruptedException {
        log.info("show任務開始!");
        Thread.sleep(5000);
        log.info("show任務結束!");
    }
}

修改啟動類 DistributedTimedTaskApplication.java:

image-20211006102416938

/**
 * 分布式定時任務應用程序
 *
 * @author BNTang
 * @date 2021/10/05
 */
@EnableAsync
@SpringBootApplication
public class DistributedTimedTaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(DistributedTimedTaskApplication.class, args);
    }

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(10);
        return threadPoolTaskScheduler;
    }
}

再次啟動工程運行效果圖如下圖所示:

image-20211006102536400

Cron 表達式

什么是 cron 表達式,一個 cron 表達式,最少有 5 個空格,來分割時間元素,Seconds Minutes Hours DayofMonth Month DayofWeek Year,Day-of-MonthDay-of-Week 不可同時為 *

組成

image-20211006103223606

通配符

,

表示列出枚舉值。例如:在 Minutes 域使用 5,20,則意味着在 5 和 20 分每分鍾觸發一次。

*

字符代表所有可能的值。* 在子表達式(月)里表示每個月的含義,* 在子表達式(日)表示每一天,在表達式(周)里表示星期的每一天,Day-of-Month 和 Day-of-Week 不可同時為 *。

?

表示不指定值。使用的場景為不需要關心當前設置這個字段的值,僅被用於(日)和(周)兩個子表達式,表示不指定值當 2 個子表達式其中之一被指定了值以后,為了避免沖突,需要將另一個子表達式的值設為 "?"。

/

"/" 字符用來指定數值的增量,在子表達式(分鍾)里的 "0/15" 表示從第 0 分鍾開始,每 15 分鍾,在子表達式(分鍾)里的 "3/20" 表示從第 3 分鍾開始,每 20 分鍾,例如在周字段上設置 "MON,WED,FRI" 表示周一,周三和周五觸發。

-

表示范圍,例如在 Minutes 域使用 5-20,表示從 5 分到 20 分鍾每分鍾觸發一次。

L

表示最后的意思,僅被用於(日)和(周)兩個子表達式,它是單詞 "last" 的縮寫。在天(月)子表達式中,“L” 表示一個月的最后一天,在天(星期)自表達式中,“L” 表示一個星期的最后一天,如果在 “L” 前有具體的內容,表示這個月的倒數第幾天,6L,最后一個星期五。

W

表示離指定日期的最近那個工作日(周一至周五),例如在日字段上設置 "15W",表示離每月 15 號最近的那個工作日觸發。如果 15 號正好是周六,則找最近的周五,如果指定格式為 "1W",它則表示每月 1 號往后最近的工作日觸發。

LW

這兩個字符可以連用,表示在某個月最后一個工作日,即最后一個星期五。

用於確定每個月第幾個星期幾,只能出現在 DayofMonth 域。例如 ”2#3” 表示在每月的第三個周二。

image-20211006124843353

QuartZ

官網:http://www.quartz-scheduler.org

引入依賴:

image-20211006140137003

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

創建執行任務:

image-20211006135125262

/**
 * @author BNTang
 * @version 1.0
 * @project distributed-TimedTask
 * @description
 * @since Created in 2021/10/6 006 13:39
 **/
@Slf4j
public class MyQuartzJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) {
        log.info("MyQuartzJob任務執行!");
    }
}

添加配置:

image-20211006140935372

/**
 * @author BNTang
 * @version 1.0
 * @project distributed-TimedTask
 * @description
 * @since Created in 2021/10/6 006 13:41
 **/
@Configuration
public class MyQuartJobConfig {
    /**
     * 可以持久化到數據庫當中
     * 多個實例共享一個數據時,就可以做到分布式
     * 實例化自己定義的Job
     *
     * @return {@link JobDetail}
     */
    @Bean
    public JobDetail jobDetail() {
        return JobBuilder.newJob(MyQuartzJob.class)
                .withIdentity("job1", "group1")
                // 設置持久化
                .storeDurably()
                .build();
    }

    /**
     * 創建觸發器,觸發實例
     *
     * @return {@link Trigger}
     */
    @Bean
    public Trigger trigger() {
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail())
                .withIdentity("trigger1", "group1")
                // 立馬啟動
                .startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule("0,2 * * * * ?"))
                .build();
    }
}

再次啟動工程運行效果圖如下圖所示:

image-20211006141031281

xxl-job

官網

概述

xxl-job 是出自大眾點評許雪里(xxl 就是作者名字的拼音首字母),的開源項目,官網上介紹這是一個輕量級分布式任務調度框架,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。跟 elasticjob 不同,xxl-job 環境依賴於 mysql,不用 ZooKeeper,這也是最大的不同。xxl-job 中心式的調度平台輕量級,開箱即用,操作簡易,上手快,與 SpringBoot 有非常好的集成,而且監控界面就集成在調度中心,界面又簡潔。對於企業維護起來成本不高,還有失敗的郵件告警等等。這就使很多企業選擇 xxl-job 做調度平台。

系統組成

調度模塊(調度中心)

負責管理調度信息,按照調度配置發出調度請求,自身不承擔業務代碼。調度系統與任務解耦,提高了系統可用性和穩定性,同時調度系統性能不再受限於任務模塊。支持可視化、簡單且動態的管理調度信息,包括任務新建,更新,刪除,任務報警等,所有上述操作都會實時生效,同時支持監控調度結果以及執行日志,支持執行器 Failover。

執行模塊(執行器)

負責接收調度請求並執行任務邏輯。任務模塊專注於任務的執行等操作,開發和維護更加簡單和高效。接收 “調度中心” 的執行請求、終止請求和日志請求等。

功能架構圖

image-20211006143151507

2 個角色

調度任務管理系統,xxl-job-admin,創建任務、設置時間、集群,使用的策略、創建任務時會指定任務名稱,地址。xxl-job-excutor,通常是我們業務系統,配置上調度系統的地址,創建任務,在任務上指定任務名稱。

搭建調度中心

下載源碼:https://github.com/xuxueli/xxl-job/releases/tag/2.3.0

執行 SQL,在下載源碼當中的 doc\db\tables_xxl_job.sql 當然我也直接貼在了下方:

#
# XXL-JOB v2.3.0
# Copyright (c) 2015-present, xuxueli.

CREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_unicode_ci;
use `xxl_job`;

SET NAMES utf8mb4;

CREATE TABLE `xxl_job_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `job_group` int(11) NOT NULL COMMENT '執行器主鍵ID',
  `job_desc` varchar(255) NOT NULL,
  `add_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  `author` varchar(64) DEFAULT NULL COMMENT '作者',
  `alarm_email` varchar(255) DEFAULT NULL COMMENT '報警郵件',
  `schedule_type` varchar(50) NOT NULL DEFAULT 'NONE' COMMENT '調度類型',
  `schedule_conf` varchar(128) DEFAULT NULL COMMENT '調度配置,值含義取決於調度類型',
  `misfire_strategy` varchar(50) NOT NULL DEFAULT 'DO_NOTHING' COMMENT '調度過期策略',
  `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '執行器路由策略',
  `executor_handler` varchar(255) DEFAULT NULL COMMENT '執行器任務handler',
  `executor_param` varchar(512) DEFAULT NULL COMMENT '執行器任務參數',
  `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞處理策略',
  `executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任務執行超時時間,單位秒',
  `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失敗重試次數',
  `glue_type` varchar(50) NOT NULL COMMENT 'GLUE類型',
  `glue_source` mediumtext COMMENT 'GLUE源代碼',
  `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE備注',
  `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新時間',
  `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任務ID,多個逗號分隔',
  `trigger_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '調度狀態:0-停止,1-運行',
  `trigger_last_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '上次調度時間',
  `trigger_next_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '下次調度時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `xxl_job_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `job_group` int(11) NOT NULL COMMENT '執行器主鍵ID',
  `job_id` int(11) NOT NULL COMMENT '任務,主鍵ID',
  `executor_address` varchar(255) DEFAULT NULL COMMENT '執行器地址,本次執行的地址',
  `executor_handler` varchar(255) DEFAULT NULL COMMENT '執行器任務handler',
  `executor_param` varchar(512) DEFAULT NULL COMMENT '執行器任務參數',
  `executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '執行器任務分片參數,格式如 1/2',
  `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失敗重試次數',
  `trigger_time` datetime DEFAULT NULL COMMENT '調度-時間',
  `trigger_code` int(11) NOT NULL COMMENT '調度-結果',
  `trigger_msg` text COMMENT '調度-日志',
  `handle_time` datetime DEFAULT NULL COMMENT '執行-時間',
  `handle_code` int(11) NOT NULL COMMENT '執行-狀態',
  `handle_msg` text COMMENT '執行-日志',
  `alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警狀態:0-默認、1-無需告警、2-告警成功、3-告警失敗',
  PRIMARY KEY (`id`),
  KEY `I_trigger_time` (`trigger_time`),
  KEY `I_handle_code` (`handle_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `xxl_job_log_report` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `trigger_day` datetime DEFAULT NULL COMMENT '調度-時間',
  `running_count` int(11) NOT NULL DEFAULT '0' COMMENT '運行中-日志數量',
  `suc_count` int(11) NOT NULL DEFAULT '0' COMMENT '執行成功-日志數量',
  `fail_count` int(11) NOT NULL DEFAULT '0' COMMENT '執行失敗-日志數量',
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `xxl_job_logglue` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `job_id` int(11) NOT NULL COMMENT '任務,主鍵ID',
  `glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE類型',
  `glue_source` mediumtext COMMENT 'GLUE源代碼',
  `glue_remark` varchar(128) NOT NULL COMMENT 'GLUE備注',
  `add_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `xxl_job_registry` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `registry_group` varchar(50) NOT NULL,
  `registry_key` varchar(255) NOT NULL,
  `registry_value` varchar(255) NOT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `xxl_job_group` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `app_name` varchar(64) NOT NULL COMMENT '執行器AppName',
  `title` varchar(12) NOT NULL COMMENT '執行器名稱',
  `address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '執行器地址類型:0=自動注冊、1=手動錄入',
  `address_list` text COMMENT '執行器地址列表,多地址逗號分隔',
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `xxl_job_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '賬號',
  `password` varchar(50) NOT NULL COMMENT '密碼',
  `role` tinyint(4) NOT NULL COMMENT '角色:0-普通用戶、1-管理員',
  `permission` varchar(255) DEFAULT NULL COMMENT '權限:執行器ID列表,多個逗號分割',
  PRIMARY KEY (`id`),
  UNIQUE KEY `i_username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `xxl_job_lock` (
  `lock_name` varchar(50) NOT NULL COMMENT '鎖名稱',
  PRIMARY KEY (`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`) VALUES (1, 'xxl-job-executor-sample', '示例執行器', 0, NULL, '2018-11-03 22:21:31' );
INSERT INTO `xxl_job_info`(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`, `schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`, `executor_handler`, `executor_param`, `executor_block_strategy`, `executor_timeout`, `executor_fail_retry_count`, `glue_type`, `glue_source`, `glue_remark`, `glue_updatetime`, `child_jobid`) VALUES (1, 1, '測試任務1', '2018-11-03 22:21:31', '2018-11-03 22:21:31', 'XXL', '', 'CRON', '0 0 0 * * ? *', 'DO_NOTHING', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代碼初始化', '2018-11-03 22:21:31', '');
INSERT INTO `xxl_job_user`(`id`, `username`, `password`, `role`, `permission`) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
INSERT INTO `xxl_job_lock` ( `lock_name`) VALUES ( 'schedule_lock');

commit;

image-20211006144542308

修改 xxl-job-admin 項目當中的 appication.properties 配置把當中的數據庫信息改為自己的數據庫信息即可如下:

image-20211006143952874

image-20211006144026467

切換到 xxl-job-admin 目錄當中打包,打包命令如下:

mvn clean -U package -Dmaven.test.skip=true

image-20211006144232995

image-20211006144311803

切換到 target 目錄當中啟動:

java -jar xxl-job-admin-2.3.0.jar --server.port=8088

image-20211006144410658

啟動之后再瀏覽器當中訪問:http://localhost:8088/xxl-job-admin/toLogin 默認的用戶名密碼為:admin/123456。

image-20211006145004871

調度任務執行流程

啟動 xxl-job-admin 調度模塊,直接運行,xxl-job-excuotr 需要配置 xxl-job-admin 的地址,主動向 xxl-job-admin 注冊。

image-20211006145222225

執行器操作

創建 SpringBoot 工程,利用初始化器創建不貼圖。

導入依賴:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.5</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>com.xuxueli</groupId>
        <artifactId>xxl-job-core</artifactId>
        <version>2.3.0</version>
    </dependency>
</dependencies>

修改配置文件添加 xxl-job 相關配置:

server:
  port: 8080
xxl:
  job:
    admin:
      addresses: http://localhost:8088/xxl-job-admin/
    executor:
      appName: xxl-job
      logPath: D:\Log

image-20211006161424855

創建配置類 XxlJobConfig.java:

/**
 * xxl-job配置
 *
 * @author 30315
 * @date 2021/10/04
 */
@Component
@Slf4j
public class XxlJobConfig {
    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;
    @Value("${xxl.job.executor.appName}")
    private String appName;
    @Value("${xxl.job.executor.logPath}")
    private String logPath;

    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appName);
        xxlJobSpringExecutor.setLogPath(logPath);
        return xxlJobSpringExecutor;
    }
}

在調度中心創建執行器與任務,在執行器管理當中創建執行器:

image-20211006170000209

執行器的名稱要和配置文件當中的 appName 名稱一樣:

image-20211006170107778

然后在切換到任務管理,創建任務:

image-20211006170258729

在程序當中創建任務:

image-20211006170753107

/**
 * @author BNTang
 * @version 1.0
 * @project xxl-job-project
 * @description
 * @since Created in 2021/10/4 004 20:52
 **/
@Component
@Slf4j
public class MyJob {
    @XxlJob("myJobHandler")
    public ReturnT<String> execute() {
        log.info("myJobHandler execute!");
        XxlJobHelper.log("myJobHandler execute!");
        return ReturnT.SUCCESS;
    }
}

啟動任務,當然在啟動任務的同時程序也要啟動起來:

image-20211006171103290

運行效果需要根據你任務的 Cron 表達式的時間來定啦,我這里不貼圖你自行測試。

路徑策略

就是一個負載均衡,當只有一個任務調度中心,有多個執行器的時候,任務調度中心要選擇一個或多個執行器來執行任務。

對項目進行集群部署:

image-20211006171421827

修改配置文件當中的端口號然后在啟動一個項目即可搭建多個服務的集群,效果如下:

image-20211006171614932

image-20211006171656096

策略詳解

image-20211006171820017

一般使用 故障轉移,當一台機器出現故障時,轉移到另一台機器上,這個故障轉移的效果需要自己搭建一個集群的服務,然后,你把集群當中正在運行任務的服務關閉之后 xxl-job 會自行的進行轉移到另外一台服務器上進行運行任務。

分片策略:

  • XxlJobHelper.getShardIndex(); 獲取當前調度器的序號
  • XxlJobHelper.getShardTotal(); 獲取總機器數量

修改 MyJob.java

/**
 * @author BNTang
 */
@Component
@Slf4j
public class MyJob {
    @XxlJob("myJobHandler")
    public ReturnT<String> execute() {
        List<Integer> users = Arrays.asList(1, 2, 3, 4, 5, 6);
        users.forEach(u -> {
            if (u % XxlJobHelper.getShardTotal() == XxlJobHelper.getShardIndex()) {
                log.info("發短信操作 >>> user={},index={},total={}",
                        u, XxlJobHelper.getShardIndex(), XxlJobHelper.getShardTotal());
            }
        });
        return ReturnT.SUCCESS;
    }
}

image-20211006200933004

阻塞處理策略

  • 單機串行
  • 丟棄后續調度
  • 覆蓋之前調度

獲取任務傳遞的,任務參數,代碼如下:

/**
 * @author BNTang
 */
@Component
@Slf4j
public class MyJob {
    @XxlJob("myJobHandler")
    public ReturnT<String> execute() {
        log.info("myJobHandler execute...");
        log.info("參數={}", XxlJobHelper.getJobParam());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        XxlJobHelper.log("myJobHandler execute...");
        return new ReturnT<>(200, "【執行成功】" + new Date());
    }
}


免責聲明!

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



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