xxl-job简单入门——学习笔记

一 简单了解

目前,我们的定时任务都是基于SpringTask来实现的。但是SpringTask存在一些问题:

  • 当微服务多实例部署时,定时任务会被执行多次。而事实上我们只需要这个任务被执行一次即可。

  • 我们除了要定时创建表,还要定时持久化Redis数据到数据库,我们希望这多个定时任务能够按照顺序依次执行,SpringTask无法控制任务顺序

不仅仅是SpringTask,其它单机使用的定时任务工具,都无法实现像这种任务执行者的调度、任务执行顺序的编排、任务监控等功能。这些功能必须要用到分布式任务调度组件。

第一节 SpringTask

我们先来看看普通定时任务的实现原理,一般定时任务中会有两个组件:

  • 任务:要执行的代码

  • 任务触发器:基于定义好的规则触发任务

而多实例部署的时候,每个启动的服务实例都会有自己的任务触发器,这样就会导致各个实例各自运行,无法统一控制:

SpringTask存在一些问题:

  • 当微服务多实例部署时,定时任务会被执行多次。而事实上我们只需要这个任务被执行一次即可。

  • 我们除了要定时创建表,还要定时持久化Redis数据到数据库,我们希望这多个定时任务能够按照顺序依次执行,SpringTask无法控制任务顺序

不仅仅是SpringTask,其它单机使用的定时任务工具,都无法实现像这种任务执行者的调度、任务执行顺序的编排、任务监控等功能。这些功能必须要用到分布式任务调度组件。

第二节 分布式调度

把任务触发器提取到各个服务实例之外,去做统一的触发、统一的调度

第三节 计数选型

其中:

  • Quartz由于功能相对比较落后,现在已经很少被使用了。

  • SchedulerX是阿里巴巴的云产品,收费。

  • PowerJob是阿里员工自己开源的一个组件,功能非常强大,不过目前市值占比还不高,还需要等待市场检验。

  • XXL-JOB:开源免费,功能虽然不如PowerJob,不过目前市场占比最高,稳定性有保证。

第二章 简单入门

第一节 了解

XXL-JOB的运行原理和架构如图:(简化过后的)

进行多实例部署时,多个执行器会注册在注册器管理器上,这时候如果要执行任务,就可以像nacos一样利用某种算法选择一个执行器来完成,不会出现SpringTask多个实例中的任务各自都执行的情况

XXL-JOB分为两部分:

  • 执行器:我们的服务引入一个XXL-JOB的依赖,就可以通过配置创建一个执行器。负责与XXL-JOB调度中心交互,执行本地任务。

  • 调度中心:一个独立服务,负责管理执行器、管理任务、任务执行的调度、任务结果和日志收集。

第二节 docker部署

分为两步:

1. 运行初始化SQL,创建数据库表

-- --------------------------------------------------------
-- 主机:                           192.168.150.101
-- 服务器版本:                        8.0.29 - MySQL Community Server - GPL
-- 服务器操作系统:                      Linux
-- HeidiSQL 版本:                  12.2.0.6576
-- --------------------------------------------------------

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;


-- 导出 xxl_job 的数据库结构
CREATE DATABASE IF NOT EXISTS `xxl_job` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `xxl_job`;

-- 导出  表 xxl_job.xxl_job_group 结构
CREATE TABLE IF NOT EXISTS `xxl_job_group` (
  `id` int NOT NULL AUTO_INCREMENT,
  `app_name` varchar(64) NOT NULL COMMENT '执行器AppName',
  `title` varchar(12) NOT NULL COMMENT '执行器名称',
  `address_type` tinyint NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入',
  `address_list` text COMMENT '执行器地址列表,多地址逗号分隔',
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_group 的数据:~2 rows (大约)
DELETE FROM `xxl_job_group`;
INSERT INTO `xxl_job_group` (`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`) VALUES
	(2, 'learning-service', '学习服务执行器', 0, NULL, '2023-02-16 20:50:48'),
	(4, 'trade-service', '交易服务执行器', 0, NULL, '2023-02-16 20:50:48'),
	(5, 'pay-service', '支付服务', 0, NULL, '2023-02-16 20:50:48'),
	(6, 'promotion-service', '促销中心', 0, NULL, '2023-02-16 20:50:48');

-- 导出  表 xxl_job.xxl_job_info 结构
CREATE TABLE IF NOT EXISTS `xxl_job_info` (
  `id` int NOT NULL AUTO_INCREMENT,
  `job_group` int 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 NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒',
  `executor_fail_retry_count` int 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 NOT NULL DEFAULT '0' COMMENT '调度状态:0-停止,1-运行',
  `trigger_last_time` bigint NOT NULL DEFAULT '0' COMMENT '上次调度时间',
  `trigger_next_time` bigint NOT NULL DEFAULT '0' COMMENT '下次调度时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_info 的数据:~5 rows (大约)
DELETE FROM `xxl_job_info`;
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`, `trigger_status`, `trigger_last_time`, `trigger_next_time`) VALUES
	(3, 4, '退款单处理', '2022-08-31 18:05:11', '2022-09-05 18:45:58', 'huyi.zhang', '', 'FIX_RATE', '300', 'DO_NOTHING', 'SHARDING_BROADCAST', 'refundRequestJobHandler', '5', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-08-31 18:05:11', '', 0, 0, 0),
	(4, 2, '持久化积分排行榜', '2022-09-02 16:57:29', '2022-09-02 16:57:29', 'huyi.zhang', '', 'CRON', '1 0 0 1 * ? *', 'DO_NOTHING', 'FIRST', 'initSeasonJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-09-02 16:57:29', '', 0, 0, 0),
	(5, 2, '持久化点赞数据', '2022-09-02 16:58:10', '2022-09-02 16:58:10', 'huyi.zhang', '', 'FIX_RATE', '120', 'DO_NOTHING', 'FIRST', 'replyLikesJobHandler', '500', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-09-02 16:58:10', '', 0, 0, 0),
	(6, 5, '未支付订单检查', '2022-09-05 18:41:46', '2022-09-05 19:17:59', 'huyi.zhang', '', 'FIX_RATE', '120', 'DO_NOTHING', 'SHARDING_BROADCAST', 'payOrderCheckHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-09-05 18:41:46', '', 0, 0, 0),
	(7, 5, '待退款订单检查', '2022-09-05 20:02:29', '2022-09-05 20:02:46', 'huyi.zhang', '', 'FIX_RATE', '123', 'DO_NOTHING', 'SHARDING_BROADCAST', 'refundOrderCheckHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-09-05 20:02:29', '', 0, 0, 0),
	(8, 6, '优惠券发放状态处理', '2022-09-16 12:23:07', '2022-09-16 12:23:07', 'huyi.zhang', '', 'FIX_RATE', '120', 'DO_NOTHING', 'SHARDING_BROADCAST', 'couponIssueJobHandler', '5', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-09-16 12:23:07', '', 0, 0, 0);

-- 导出  表 xxl_job.xxl_job_lock 结构
CREATE TABLE IF NOT EXISTS `xxl_job_lock` (
  `lock_name` varchar(50) NOT NULL COMMENT '锁名称',
  PRIMARY KEY (`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_lock 的数据:~0 rows (大约)
DELETE FROM `xxl_job_lock`;
INSERT INTO `xxl_job_lock` (`lock_name`) VALUES
	('schedule_lock');

-- 导出  表 xxl_job.xxl_job_log 结构
CREATE TABLE IF NOT EXISTS `xxl_job_log` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `job_group` int NOT NULL COMMENT '执行器主键ID',
  `job_id` int 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 NOT NULL DEFAULT '0' COMMENT '失败重试次数',
  `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
  `trigger_code` int NOT NULL COMMENT '调度-结果',
  `trigger_msg` text COMMENT '调度-日志',
  `handle_time` datetime DEFAULT NULL COMMENT '执行-时间',
  `handle_code` int NOT NULL COMMENT '执行-状态',
  `handle_msg` text COMMENT '执行-日志',
  `alarm_status` tinyint 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 AUTO_INCREMENT=92 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_log 的数据:~0 rows (大约)
DELETE FROM `xxl_job_log`;

-- 导出  表 xxl_job.xxl_job_logglue 结构
CREATE TABLE IF NOT EXISTS `xxl_job_logglue` (
  `id` int NOT NULL AUTO_INCREMENT,
  `job_id` int 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 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_logglue 的数据:~0 rows (大约)
DELETE FROM `xxl_job_logglue`;

-- 导出  表 xxl_job.xxl_job_log_report 结构
CREATE TABLE IF NOT EXISTS `xxl_job_log_report` (
  `id` int NOT NULL AUTO_INCREMENT,
  `trigger_day` datetime DEFAULT NULL COMMENT '调度-时间',
  `running_count` int NOT NULL DEFAULT '0' COMMENT '运行中-日志数量',
  `suc_count` int NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量',
  `fail_count` int NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量',
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=173 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_log_report 的数据:~136 rows (大约)
DELETE FROM `xxl_job_log_report`;
INSERT INTO `xxl_job_log_report` (`id`, `trigger_day`, `running_count`, `suc_count`, `fail_count`, `update_time`) VALUES
	(1, '2022-06-14 00:00:00', 0, 0, 0, NULL),
	(2, '2022-06-13 00:00:00', 0, 0, 0, NULL),
	(3, '2022-06-12 00:00:00', 0, 0, 0, NULL),
	(4, '2022-08-16 00:00:00', 0, 0, 0, NULL),
	(5, '2022-08-15 00:00:00', 0, 0, 0, NULL),
	(6, '2022-08-14 00:00:00', 0, 0, 0, NULL),
	(7, '2022-08-17 00:00:00', 0, 0, 0, NULL),
	(8, '2022-08-20 00:00:00', 0, 0, 0, NULL),
	(9, '2022-08-19 00:00:00', 0, 0, 0, NULL),
	(10, '2022-08-18 00:00:00', 0, 0, 0, NULL),
	(11, '2022-08-21 00:00:00', 0, 0, 0, NULL),
	(12, '2022-08-22 00:00:00', 0, 0, 0, NULL),
	(13, '2022-08-23 00:00:00', 0, 0, 0, NULL),
	(14, '2022-08-24 00:00:00', 0, 0, 0, NULL),
	(15, '2022-08-25 00:00:00', 0, 0, 0, NULL),
	(16, '2022-08-26 00:00:00', 0, 0, 0, NULL),
	(17, '2022-08-27 00:00:00', 0, 0, 0, NULL),
	(18, '2022-08-29 00:00:00', 0, 0, 0, NULL),
	(19, '2022-08-28 00:00:00', 0, 0, 0, NULL),
	(20, '2022-08-30 00:00:00', 0, 0, 0, NULL),
	(21, '2022-08-31 00:00:00', 0, 6, 6, NULL),
	(22, '2022-09-02 00:00:00', 0, 2, 1, NULL),
	(23, '2022-09-01 00:00:00', 0, 0, 0, NULL),
	(24, '2022-09-03 00:00:00', 0, 0, 0, NULL),
	(25, '2022-09-05 00:00:00', 0, 5, 6, NULL),
	(26, '2022-09-04 00:00:00', 0, 0, 0, NULL),
	(27, '2022-09-06 00:00:00', 0, 0, 0, NULL),
	(28, '2022-09-07 00:00:00', 0, 0, 0, NULL),
	(29, '2022-09-08 00:00:00', 0, 0, 0, NULL),
	(30, '2022-09-09 00:00:00', 0, 0, 0, NULL),
	(31, '2022-09-13 00:00:00', 0, 0, 0, NULL),
	(32, '2022-09-12 00:00:00', 0, 0, 0, NULL),
	(33, '2022-09-11 00:00:00', 0, 0, 0, NULL),
	(34, '2022-09-14 00:00:00', 0, 0, 0, NULL),
	(35, '2022-09-15 00:00:00', 0, 0, 0, NULL),
	(36, '2022-09-16 00:00:00', 0, 6, 1, NULL),
	(37, '2022-09-17 00:00:00', 0, 0, 0, NULL),
	(38, '2022-09-19 00:00:00', 0, 0, 0, NULL),
	(39, '2022-09-18 00:00:00', 0, 0, 0, NULL),
	(40, '2022-09-20 00:00:00', 0, 0, 0, NULL),
	(41, '2022-09-21 00:00:00', 0, 0, 0, NULL),
	(42, '2022-09-22 00:00:00', 0, 0, 0, NULL),
	(43, '2022-09-23 00:00:00', 0, 0, 0, NULL),
	(44, '2022-09-24 00:00:00', 0, 0, 0, NULL),
	(45, '2022-09-26 00:00:00', 0, 0, 0, NULL),
	(46, '2022-09-25 00:00:00', 0, 0, 0, NULL),
	(47, '2022-09-27 00:00:00', 0, 0, 0, NULL),
	(48, '2022-09-28 00:00:00', 0, 0, 0, NULL),
	(49, '2022-09-29 00:00:00', 0, 0, 0, NULL),
	(50, '2022-09-30 00:00:00', 0, 0, 0, NULL),
	(51, '2022-10-02 00:00:00', 0, 0, 0, NULL),
	(52, '2022-10-01 00:00:00', 0, 0, 0, NULL),
	(53, '2022-10-06 00:00:00', 0, 7, 2, NULL),
	(54, '2022-10-05 00:00:00', 0, 0, 0, NULL),
	(55, '2022-10-04 00:00:00', 0, 0, 0, NULL),
	(56, '2022-10-07 00:00:00', 0, 0, 0, NULL),
	(57, '2022-10-08 00:00:00', 0, 0, 0, NULL),
	(58, '2022-10-09 00:00:00', 0, 0, 0, NULL),
	(59, '2022-10-10 00:00:00', 0, 0, 0, NULL),
	(60, '2022-10-11 00:00:00', 0, 0, 0, NULL),
	(61, '2022-10-12 00:00:00', 0, 0, 0, NULL),
	(62, '2022-10-13 00:00:00', 0, 0, 0, NULL),
	(63, '2022-10-14 00:00:00', 0, 0, 0, NULL),
	(64, '2022-10-17 00:00:00', 0, 0, 0, NULL),
	(65, '2022-10-16 00:00:00', 0, 0, 0, NULL),
	(66, '2022-10-15 00:00:00', 0, 0, 0, NULL),
	(67, '2022-10-18 00:00:00', 0, 0, 0, NULL),
	(68, '2022-10-19 00:00:00', 0, 0, 0, NULL),
	(69, '2022-10-20 00:00:00', 0, 0, 0, NULL),
	(70, '2022-10-21 00:00:00', 0, 0, 0, NULL),
	(71, '2022-10-22 00:00:00', 0, 0, 0, NULL),
	(72, '2022-10-24 00:00:00', 0, 0, 0, NULL),
	(73, '2022-10-23 00:00:00', 0, 0, 0, NULL),
	(74, '2022-10-25 00:00:00', 0, 0, 0, NULL),
	(75, '2022-10-26 00:00:00', 0, 2, 0, NULL),
	(76, '2022-10-27 00:00:00', 0, 0, 0, NULL),
	(77, '2022-10-28 00:00:00', 0, 0, 0, NULL),
	(78, '2022-10-30 00:00:00', 0, 0, 0, NULL),
	(79, '2022-10-29 00:00:00', 0, 0, 0, NULL),
	(80, '2022-10-31 00:00:00', 0, 0, 0, NULL),
	(81, '2022-11-02 00:00:00', 0, 0, 0, NULL),
	(82, '2022-11-01 00:00:00', 0, 0, 0, NULL),
	(83, '2022-11-03 00:00:00', 0, 3, 3, NULL),
	(84, '2022-11-04 00:00:00', 0, 0, 0, NULL),
	(85, '2022-11-05 00:00:00', 0, 0, 0, NULL),
	(86, '2022-11-06 00:00:00', 0, 0, 0, NULL),
	(87, '2022-11-07 00:00:00', 0, 0, 0, NULL),
	(88, '2022-11-08 00:00:00', 0, 0, 0, NULL),
	(89, '2022-11-09 00:00:00', 0, 0, 0, NULL),
	(90, '2022-11-10 00:00:00', 0, 0, 0, NULL),
	(91, '2022-11-11 00:00:00', 0, 0, 0, NULL),
	(92, '2022-11-12 00:00:00', 0, 0, 0, NULL),
	(93, '2022-11-14 00:00:00', 0, 0, 0, NULL),
	(94, '2022-11-13 00:00:00', 0, 0, 0, NULL),
	(95, '2022-11-15 00:00:00', 0, 0, 0, NULL),
	(96, '2022-11-16 00:00:00', 0, 0, 0, NULL),
	(97, '2022-11-18 00:00:00', 0, 0, 0, NULL),
	(98, '2022-11-17 00:00:00', 0, 0, 0, NULL),
	(99, '2022-11-19 00:00:00', 0, 0, 0, NULL),
	(100, '2022-11-21 00:00:00', 0, 0, 0, NULL),
	(101, '2022-11-20 00:00:00', 0, 0, 0, NULL),
	(102, '2022-11-22 00:00:00', 0, 0, 0, NULL),
	(103, '2022-11-23 00:00:00', 0, 0, 0, NULL),
	(104, '2022-11-28 00:00:00', 0, 0, 0, NULL),
	(105, '2022-11-27 00:00:00', 0, 0, 0, NULL),
	(106, '2022-11-26 00:00:00', 0, 0, 0, NULL),
	(107, '2022-11-29 00:00:00', 0, 0, 0, NULL),
	(108, '2022-11-30 00:00:00', 0, 0, 0, NULL),
	(109, '2022-12-01 00:00:00', 0, 0, 0, NULL),
	(110, '2022-12-02 00:00:00', 0, 0, 0, NULL),
	(111, '2022-12-03 00:00:00', 0, 0, 0, NULL),
	(112, '2022-12-04 00:00:00', 0, 0, 0, NULL),
	(113, '2022-12-05 00:00:00', 0, 0, 0, NULL),
	(114, '2022-12-09 00:00:00', 0, 0, 0, NULL),
	(115, '2022-12-08 00:00:00', 0, 0, 0, NULL),
	(116, '2022-12-07 00:00:00', 0, 0, 0, NULL),
	(117, '2022-12-10 00:00:00', 0, 0, 0, NULL),
	(118, '2022-12-11 00:00:00', 0, 0, 0, NULL),
	(119, '2022-12-21 00:00:00', 0, 0, 0, NULL),
	(120, '2022-12-20 00:00:00', 0, 0, 0, NULL),
	(121, '2022-12-19 00:00:00', 0, 0, 0, NULL),
	(122, '2022-12-22 00:00:00', 0, 0, 0, NULL),
	(123, '2022-12-26 00:00:00', 0, 0, 0, NULL),
	(124, '2022-12-25 00:00:00', 0, 0, 0, NULL),
	(125, '2022-12-24 00:00:00', 0, 0, 0, NULL),
	(126, '2022-12-27 00:00:00', 0, 0, 0, NULL),
	(127, '2022-12-28 00:00:00', 0, 0, 0, NULL),
	(128, '2022-12-29 00:00:00', 0, 0, 0, NULL),
	(129, '2022-12-31 00:00:00', 0, 0, 0, NULL),
	(130, '2022-12-30 00:00:00', 0, 0, 0, NULL),
	(131, '2023-01-01 00:00:00', 0, 0, 0, NULL),
	(132, '2023-01-02 00:00:00', 0, 0, 0, NULL),
	(133, '2023-01-05 00:00:00', 0, 0, 0, NULL),
	(134, '2023-01-04 00:00:00', 0, 0, 0, NULL),
	(135, '2023-01-03 00:00:00', 0, 0, 0, NULL),
	(136, '2023-01-06 00:00:00', 0, 0, 0, NULL),
	(137, '2023-01-07 00:00:00', 0, 0, 0, NULL),
	(138, '2023-01-08 00:00:00', 0, 0, 0, NULL),
	(139, '2023-01-09 00:00:00', 0, 0, 0, NULL),
	(140, '2023-01-10 00:00:00', 0, 0, 0, NULL),
	(141, '2023-01-11 00:00:00', 0, 0, 0, NULL),
	(142, '2023-01-12 00:00:00', 0, 0, 0, NULL),
	(143, '2023-01-13 00:00:00', 0, 0, 0, NULL),
	(144, '2023-01-14 00:00:00', 0, 0, 0, NULL),
	(145, '2023-01-15 00:00:00', 0, 0, 0, NULL),
	(146, '2023-01-16 00:00:00', 0, 0, 0, NULL),
	(147, '2023-01-17 00:00:00', 0, 0, 0, NULL),
	(148, '2023-01-18 00:00:00', 0, 0, 0, NULL),
	(149, '2023-01-26 00:00:00', 0, 0, 0, NULL),
	(150, '2023-01-25 00:00:00', 0, 0, 0, NULL),
	(151, '2023-01-24 00:00:00', 0, 0, 0, NULL),
	(152, '2023-01-27 00:00:00', 0, 0, 0, NULL),
	(153, '2023-01-28 00:00:00', 0, 0, 0, NULL),
	(154, '2023-01-29 00:00:00', 0, 0, 0, NULL),
	(155, '2023-01-30 00:00:00', 0, 0, 0, NULL),
	(156, '2023-01-31 00:00:00', 0, 0, 0, NULL),
	(157, '2023-02-01 00:00:00', 0, 0, 0, NULL),
	(158, '2023-02-02 00:00:00', 0, 0, 0, NULL),
	(159, '2023-02-03 00:00:00', 0, 0, 0, NULL),
	(160, '2023-02-04 00:00:00', 0, 0, 0, NULL),
	(161, '2023-02-05 00:00:00', 0, 0, 0, NULL),
	(162, '2023-02-06 00:00:00', 0, 0, 0, NULL),
	(163, '2023-02-07 00:00:00', 0, 0, 0, NULL),
	(164, '2023-02-08 00:00:00', 0, 0, 0, NULL),
	(165, '2023-02-09 00:00:00', 0, 0, 0, NULL),
	(166, '2023-02-10 00:00:00', 0, 0, 0, NULL),
	(167, '2023-02-11 00:00:00', 0, 0, 0, NULL),
	(168, '2023-02-12 00:00:00', 0, 0, 0, NULL),
	(169, '2023-02-13 00:00:00', 0, 0, 0, NULL),
	(170, '2023-02-14 00:00:00', 0, 0, 0, NULL),
	(171, '2023-02-15 00:00:00', 0, 0, 0, NULL),
	(172, '2023-02-16 00:00:00', 0, 0, 0, NULL);

-- 导出  表 xxl_job.xxl_job_registry 结构
CREATE TABLE IF NOT EXISTS `xxl_job_registry` (
  `id` int 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 AUTO_INCREMENT=287 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_registry 的数据:~0 rows (大约)
DELETE FROM `xxl_job_registry`;

-- 导出  表 xxl_job.xxl_job_user 结构
CREATE TABLE IF NOT EXISTS `xxl_job_user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '账号',
  `password` varchar(50) NOT NULL COMMENT '密码',
  `role` tinyint NOT NULL COMMENT '角色:0-普通用户、1-管理员',
  `permission` varchar(255) DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割',
  PRIMARY KEY (`id`),
  UNIQUE KEY `i_username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- 正在导出表  xxl_job.xxl_job_user 的数据:~2 rows (大约)
DELETE FROM `xxl_job_user`;
INSERT INTO `xxl_job_user` (`id`, `username`, `password`, `role`, `permission`) VALUES
	(1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL),
	(2, 'test', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);

/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
  • 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:系统用户表;

2. 利用Docker命令,创建并运行容器(记得改一下ip等信息)

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

第三节 微服务集成xxl-job

1. 依赖

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

2. 配置执行器

@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
    logger.info(">>>>>>>>>>> xxl-job config init.");
    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;
}

参数说明:

  • adminAddress:调度中心地址,天机学堂中就是填虚拟机地址

  • appname:微服务名称

  • ip和port:当前执行器的ip和端口,无需配置,自动获取

  • accessToken:访问令牌,在调度中心中配置令牌,所有执行器访问时都必须携带该令牌,否则无法访问。咱们项目的令牌已经配好,就是tianji。如果要修改,可以到虚拟机的/usr/local/src/xxl-job/application.properties文件中,修改xxl.job.accessToken属性,然后重启XXL-JOB即可。

  • logPath:任务运行日志的保存目录

  • logRetentionDays:日志最长保留时长

自动装配代码:

1. 配置属性类:

package com.tianji.common.autoconfigure.xxljob;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "tj.xxl-job")
public class XxlJobProperties {

    private String accessToken;
    private Admin admin;
    private Executor executor;

    @Data
    public static class Admin {
        private String address;
    }

    @Data
    public static class Executor {
        private String appName;
        private String address;
        private String ip;
        private Integer port;
        private String logPath;
        private Integer logRetentionDays;

    }
}

2. 自动装配类:

package com.tianji.common.autoconfigure.xxljob;

import com.tianji.common.utils.StringUtils;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
@ConditionalOnClass(XxlJobSpringExecutor.class)
@EnableConfigurationProperties(XxlJobProperties.class)
public class XxlJobConfig {

    @Bean
    public XxlJobSpringExecutor xxlJobExecutor(XxlJobProperties prop) {
        log.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        XxlJobProperties.Admin admin = prop.getAdmin();
        if (admin != null && StringUtils.isNotEmpty(admin.getAddress())) {
            xxlJobSpringExecutor.setAdminAddresses(admin.getAddress());
        }
        XxlJobProperties.Executor executor = prop.getExecutor();
        if (executor != null) {
            if (executor.getAppName() != null)
                xxlJobSpringExecutor.setAppname(executor.getAppName());
            if (executor.getIp() != null)
                xxlJobSpringExecutor.setIp(executor.getIp());
            if (executor.getPort() != null)
                xxlJobSpringExecutor.setPort(executor.getPort());
            if (executor.getLogPath() != null)
                xxlJobSpringExecutor.setLogPath(executor.getLogPath());
            if (executor.getLogRetentionDays() != null)
                xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays());
        }
        if (prop.getAccessToken() != null)
            xxlJobSpringExecutor.setAccessToken(prop.getAccessToken());
        log.info(">>>>>>>>>>> xxl-job config end.");
        return xxlJobSpringExecutor;
    }
}

3. 配置文件:——记得改一下ip,端口,服务名等

tj:
  xxl-job:
    access-token: tianji
    admin:
      address: http://192.168.150.101:8880/xxl-job-admin
    executor:
      appname: ${spring.application.name}
      log-retention-days: 10
      logPath: job/${spring.application.name}

4. 编写任务:——注解要改

第四节 注册执行器,配置任务

1. 注册执行器:

进入网址(记得改ip):http://192.168.150.101:8880/xxl-job-admin

输入用户名密码(用自己的,这里的是我上面的代码里写的账户密码):admin/123456

接下来,重启tj-learning服务,登录XXL-JOB控制台,注册执行器。

AppName:就是你微服务的服务名

名称:无所谓

注册方式:选择自动注册就不用填下面的机器地址,否则就要输入宿主机的地址

2. 配置任务

其中比较关键的几个配置:

  • 调度配置:也就是什么时候执行,一般选择cron表达式

  • 任务配置:采用BEAN模式,指定JobHandler,这里指定的就是在项目中@XxlJob注解中的任务名称

  • 路由策略:就是指如果有多个任务执行器,该由谁执行?这里支持的策略非常多:

路由策略说明:

  • FIRST(第一个):固定选择第一个执行器;

  • LAST(最后一个):固定选择最后一个执行器;

  • ROUND(轮询):在线的执行器按照轮询策略选择一个执行

  • RANDOM(随机):随机选择在线的执行器;

  • CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台执行器,且所有任务均匀散列在不同执行器上。

  • LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的执行器优先被选举;

  • LEAST_RECENTLY_USED(最近最久未使用):最久未使用的执行器优先被选举;

  • FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的执行器选定为目标执行器并发起调度;

  • BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的执行器选定为目标执行器并发起调度;

  • SHARDING_BROADCAST(分片广播):广播触发对应集群中所有执行器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务

第五节 测试

如果需要测试,可以如下图执行一次:

查看日志:

第六节 任务链

在任务管理列表,我们会发现每个任务都有自己的任务id

然后我们选择第一个需要执行的任务,点击编辑

然后在子任务中,填写持久化榜单数据任务的id,本例中是12:

那么在执行完这个任务后,id为12的任务就是下一个执行对象,我们还可以为id为12的任务定义子任务,这样就形成了一条任务链

第三章 策略

第一节 数据分片

如果一次操作的数据量过大,我们一般会考虑采用分页,一批一批的操作。而数据量过于庞大的话,完成业务就过于耗时了。

如果说服务采用多实例部署,那我们其实可以采用数据分片。我们把数据分成多个小部分

  • 起始页码:执行器编号是多少,起始页码就是多少

  • 页跨度:执行器有几个,跨度就是多少。也就是说你要跳过别人读取过的页码

分页起始页码就是数据分片的编号(index

起始页码和页跨度我们都可以从xxl-job里获得:

那么分片处理数据的代码参考如下:——注意定义起始页面和翻页的代码

// 3.2.查询数据
    int index = XxlJobHelper.getShardIndex();
    int total = XxlJobHelper.getShardTotal();
    int pageNo = index + 1; // 起始页,就是分片序号+1 !!!!!
    int pageSize = 10;
    while (true) {
        List<PointsBoard> boardList = pointsBoardService.queryCurrentBoardList(key, pageNo, pageSize);
        if (CollUtils.isEmpty(boardList)) {
            break;
        }
        // 4.持久化到数据库
        // 4.1.把排名信息写入id
        boardList.forEach(b -> {
            b.setId(b.getRank().longValue());
            b.setRank(null);
        });
        // 4.2.持久化
        pointsBoardService.saveBatch(boardList);
        // 5.翻页,跳过N个页,N就是分片数量 !!!!!
        pageNo+=total;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值