Springboot + Quartz 实现分布式定时任务集群

  • quartz 概念
  • Quartz 工作原理
  • Quartz 分布式集群定时任务实现
  • 代码地址(可参考实现)

Quart 官方介绍:https://github.com/quartz-scheduler/quartz/blob/master/docs/introduction.adoc
本文学习参考:https://blog.csdn.net/sqlgao22/article/details/100669377

quartz 概念

一、什么是 Quartz?
如果仅仅只是使用定时任务,可以使用 spring 的schedule 实现,方便、代码量少、易于实现。但是当使用分布式进行部署的时候,就会出现所有的服务器都在跑同一个定时任务,出现一个定时任务被执行多次的情况。那么最好的方式是使用 quartz 进行定时任务的调度。即:quartz 是一个为了解决分布式定时任务的导致任务重复调度的框架。效果就是,起多个工程,同一个定时任务只会在一个工程上跑。

二、Quartz 的优点
1、可以实现多个定时任务进行调度。
2、可以实现代码的解耦,通过配置文件的当时进行配置。
3、功能强大,可以通过 cron 表达式设置复杂的时间任务调度。

三、Quartz 核心点
1、Job (被调度的任务接口):我们需要实现 Job ,和继承 TimerTask 重写 run 方法一样,重写 Job 中的 excute 方法,excute 方法是任务调度的方法执行位置。
2、JobDetail:必须通过 JobDetail 来实现 Job 实例(基于 builder 模式实现的)。
3、Trigger(包括 CronTrigger 和 SimpleTrigger):指定任务调度的频率时间。何时进行任务调度(基于 builder 模式实现的)触发器。
4、Scheduler:结合 JobDetail 实例和 Trigger 实例,进行任务的触发的调度器(基于 Factory 模式)。

Quartz 工作原理

一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。意思是你必须对每个节点分别启动或停止。不像许多应用服务器的集群,独立的 Quartz 节点并不是与另一节点或管理节点通信。Quartz 应用是通过数据库表来感知到另一个应用的。离开 db 将无法感知。

Quartz 分布式集群定时任务实现

注意事项: 因为 Quartz 集依赖于数据库,所以必须首先创建 Quartz 数据库表。Quartz 包括了所有被支持的数据库平台的 SQL脚本。本文以 MySQL 为例。注意:创建的表表名都是小写的,在代码中使用的是大写的表名;在liunx中的mysql数据库默认是大小写敏感的,因此使用liunx的数据库会出现找不到表的情况,酌情修改表或是改变数据库配置。

一、导入数据库表

表中所有字段详解:https://blog.csdn.net/sqlgao22/article/details/100697214

/*
Navicat MySQL Data Transfer
Source Server         : 192.168.163.128_3306
Source Server Version : 50540
Source Host           : 192.168.163.128:3306
Source Database       : primer
Target Server Type    : MYSQL
Target Server Version : 50540
File Encoding         : 65001
Date: 2018-08-29 22:56:23
*/SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for qrtz_blob_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_blob_triggers`;
CREATE TABLE `qrtz_blob_triggers` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`BLOB_DATA` blob,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_calendars
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_calendars`;
CREATE TABLE `qrtz_calendars` (`SCHED_NAME` varchar(120) NOT NULL,`CALENDAR_NAME` varchar(200) NOT NULL,`CALENDAR` blob NOT NULL,PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_cron_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_cron_triggers`;
CREATE TABLE `qrtz_cron_triggers` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`CRON_EXPRESSION` varchar(120) NOT NULL,`TIME_ZONE_ID` varchar(80) DEFAULT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_fired_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_fired_triggers`;
CREATE TABLE `qrtz_fired_triggers` (`SCHED_NAME` varchar(120) NOT NULL,`ENTRY_ID` varchar(95) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`INSTANCE_NAME` varchar(200) NOT NULL,`FIRED_TIME` bigint(13) NOT NULL,`SCHED_TIME` bigint(13) NOT NULL,`PRIORITY` int(11) NOT NULL,`STATE` varchar(16) NOT NULL,`JOB_NAME` varchar(200) DEFAULT NULL,`JOB_GROUP` varchar(200) DEFAULT NULL,`IS_NONCONCURRENT` varchar(1) DEFAULT NULL,`REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_job_details
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_job_details`;
CREATE TABLE `qrtz_job_details` (`SCHED_NAME` varchar(120) NOT NULL,`JOB_NAME` varchar(200) NOT NULL,`JOB_GROUP` varchar(200) NOT NULL,`DESCRIPTION` varchar(250) DEFAULT NULL,`JOB_CLASS_NAME` varchar(250) NOT NULL,`IS_DURABLE` varchar(1) NOT NULL,`IS_NONCONCURRENT` varchar(1) NOT NULL,`IS_UPDATE_DATA` varchar(1) NOT NULL,`REQUESTS_RECOVERY` varchar(1) NOT NULL,`JOB_DATA` blob,PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_locks
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_locks`;
CREATE TABLE `qrtz_locks` (`SCHED_NAME` varchar(120) NOT NULL,`LOCK_NAME` varchar(40) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_paused_trigger_grps
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
CREATE TABLE `qrtz_paused_trigger_grps` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_scheduler_state
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_scheduler_state`;
CREATE TABLE `qrtz_scheduler_state` (`SCHED_NAME` varchar(120) NOT NULL,`INSTANCE_NAME` varchar(200) NOT NULL,`LAST_CHECKIN_TIME` bigint(13) NOT NULL,`CHECKIN_INTERVAL` bigint(13) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_simple_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_simple_triggers`;
CREATE TABLE `qrtz_simple_triggers` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`REPEAT_COUNT` bigint(7) NOT NULL,`REPEAT_INTERVAL` bigint(12) NOT NULL,`TIMES_TRIGGERED` bigint(10) NOT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_simprop_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
CREATE TABLE `qrtz_simprop_triggers` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`STR_PROP_1` varchar(512) DEFAULT NULL,`STR_PROP_2` varchar(512) DEFAULT NULL,`STR_PROP_3` varchar(512) DEFAULT NULL,`INT_PROP_1` int(11) DEFAULT NULL,`INT_PROP_2` int(11) DEFAULT NULL,`LONG_PROP_1` bigint(20) DEFAULT NULL,`LONG_PROP_2` bigint(20) DEFAULT NULL,`DEC_PROP_1` decimal(13,4) DEFAULT NULL,`DEC_PROP_2` decimal(13,4) DEFAULT NULL,`BOOL_PROP_1` varchar(1) DEFAULT NULL,`BOOL_PROP_2` varchar(1) DEFAULT NULL,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for qrtz_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_triggers`;
CREATE TABLE `qrtz_triggers` (`SCHED_NAME` varchar(120) NOT NULL,`TRIGGER_NAME` varchar(200) NOT NULL,`TRIGGER_GROUP` varchar(200) NOT NULL,`JOB_NAME` varchar(200) NOT NULL,`JOB_GROUP` varchar(200) NOT NULL,`DESCRIPTION` varchar(250) DEFAULT NULL,`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,`PREV_FIRE_TIME` bigint(13) DEFAULT NULL,`PRIORITY` int(11) DEFAULT NULL,`TRIGGER_STATE` varchar(16) NOT NULL,`TRIGGER_TYPE` varchar(8) NOT NULL,`START_TIME` bigint(13) NOT NULL,`END_TIME` bigint(13) DEFAULT NULL,`CALENDAR_NAME` varchar(200) DEFAULT NULL,`MISFIRE_INSTR` smallint(2) DEFAULT NULL,`JOB_DATA` blob,PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

二、引入 pom 依赖

     <!--spring与quartz依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><!--druid连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.12</version></dependency>

三、引入 quartz.properties 配置文件

注意:使用分布式集群跑定时任务,需要使用 db 持久化,所以需要所有的节点共享一个数据源。

#============================================================================
# Configure JobStore
# Using Spring datasource in SchedulerConfig.java
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
#============================================================================
org.quartz.jobStore.useProperties=false
#表名的前缀
org.quartz.jobStore.tablePrefix = qrtz_
#isClustered 属性为 true,你就告诉了 Scheduler 实例要它参与到一个集群当中
org.quartz.jobStore.isClustered = true
#clusterCheckinInterval 属性定义了Scheduler 实例检入到数据库中的频率(单位:毫秒),默认值是 15000
org.quartz.jobStore.clusterCheckinInterval = 3000
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.txIsolationLevelReadCommitted = true
#class属性为 JobStoreTX,将任务持久化到数据中。quartz依赖于数据库查询任务状态
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate#============================================================================
# Configure Main Scheduler Properties
# Needed to manage cluster instances
#============================================================================
#instanceName属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同。
org.quartz.scheduler.instanceName = ClusterQuartz
#instanceId 属性为 AUTO即可,基于主机名和时间戳来产生实例 ID
org.quartz.scheduler.instanceId= AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false#============================================================================
# Configure ThreadPool
# Can also be configured in spring configuration
# 此处使用的java的线程池
#============================================================================
#org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#org.quartz.threadPool.threadCount = 5
#org.quartz.threadPool.threadPriority = 5
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

四、springboot与quartz配置
1、当在定时任务的job中进行属性注入的时候就会发现所有的对象都无法使用Autowired进行注入,会有空指针异常抛出。
原因:
Quartz初始化是自己的JobContext,不同于Spring的ApplicationContext,所以无法直接注入,导致使用时产生空指针异常!
版本也有关系:
spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错。至于原因,则是spring对于quartz的支持实现org.springframework.scheduling.quartz.CronTriggerBean继承了org.quartz.CronTrigger,在quartz1.x系列中org.quartz.CronTrigger是个类,而在quartz2.x系列中org.quartz.CronTrigger变成了接口,从而造成无法用spring的方式配置quartz的触发器(trigger)。

解决方式: 自定义一个类.继承JobFactory.重写createInstance方法。

@Component
public class MyJobFactory extends SpringBeanJobFactory {@Autowired//注入autowire的对象工厂private AutowireCapableBeanFactory beanFactory;//重写Job工厂的createJobInstance方法@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Object object = super.createJobInstance(bundle);//在autowired中手动加入创建出来的对象beanFactory.autowireBean(object);return object;}
}

代码地址(可参考实现)

Springboot + Quartz 实现分布式定时任务集群
github 地址:https://github.com/1914526816lhw/cloud-microservice/tree/master/quartz-time-task-service7003

Springboot + Quartz 实现分布式定时任务集群相关推荐

  1. zk和quartz实现分布式定时调度

    zk和quartz实现分布式定时调度 https://blog.csdn.net/lanjian056/article/details/52711318

  2. 解决springboot + quartz的分布式问题以及dolphinscheduler

    springboot + quartz 将quartz存储默认在内存中, 多节点部署时存在分布式问题. 改成基于数据库的quartz分布式集群解决方案, 参考官方文档, 需要为quartz单独配置da ...

  3. Spring+Quartz定时任务集群环境下部署的解决方法

    1.配置quartz.properties文件,如下 #======================================================================== ...

  4. 第四十章:基于SpringBoot Quartz完成定时任务分布式多节点负载持久化

    在上一章[第三十九章:基于SpringBoot & Quartz完成定时任务分布式单节点持久化]中我们已经完成了任务的持久化,当我们创建一个任务时任务会被quartz定时任务框架自动持久化到数 ...

  5. quarts集群 运维_分布式定时任务调度系统技术解决方案(xxl-job、Elastic-job、Saturn)...

    1.业务场景 保险人管系统每月工资结算,平安有150万代理人,如何快速的进行工资结算(数据运算型) 保险短信开门红/电商双十一 1000w+短信发送(短时汇聚型) 工作中业务场景非常多,所涉及到的场景 ...

  6. 分布式定时任务调度框架Quartz

    文章目录 一.Quartz引言 二.Quartz使用 2.1 导入依赖 2.2 定义Job 2.3 API测试 2.3.1 细节 2.4 配置 2.5 核心类说明 三.Trigger触发器 3.1 S ...

  7. 分布式定时任务调度实战

    目录 1.为什么需要定时任务 2.定时任务调度框架 2.1 单机 2.2 分布 3.xxl-job和elastic-job对比 3.1 支持集群部署方式 3.2 多节点部署任务执行方式 3.3 日志可 ...

  8. 分布式定时任务调度系统技术选型

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:EFbiz blog.csdn.net/guyue35/ar ...

  9. 使用Spring Boot + Quartz 实现分布式定时任务平台

    本文将从项目实战出发来介绍分布式定时任务的实现.在某些应用场景下要求任务必须具备高可用性和可扩展性,单台服务器不能满足业务需求,这时就需要使用Quartz实现分布式定时任务. 一.分布式任务应用场景 ...

  10. Quartz.Net分布式任务管理平台(第二版)

    前言:在Quartz.Net项目发布第一版Quartz.Net分布式任务管理平台后,有挺多园友去下载使用,我们通过QQ去探讨,其中项目中还是存在一定的不完善.所以有了现在这个版本.这个版本的编写完成其 ...

最新文章

  1. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition
  2. 十八、中断之独立按键
  3. 项目上传github步骤
  4. shell 删除七日内日志_SHELL脚本:定期清理日志文件
  5. Apache ab 测试结果的分析
  6. Python基础知识:字符串
  7. python实现web服务器_python实现web服务器
  8. Docker容器commit安装kali工具集
  9. nyoj-488 素数环 +nyoj -32 组合数 (搜索)
  10. js练习4(注册验证)
  11. python生成三维点云包围盒
  12. 【新知实验室 腾讯云TRTC实时音视频体验】
  13. tp交换机管理页面_tplink交换机设置步骤使用方法
  14. 新西兰计算机预科学费,新西兰留学预科学费
  15. 全世界最好的编辑器VIM之Windows配置(gvim)
  16. appinventor拓展开发
  17. 响应式卡片悬停效果 html+css
  18. Attention模型超超超超超超级攻略
  19. python多线程、多进程
  20. python求三个数平均值_python求三个数平均值

热门文章

  1. 传智播客黑马程序员_新程序员的最佳播客,以及聆听他们的最佳工具
  2. 中国地图3D立体效果
  3. Win10如何开启IIS服务以及如何打开IIS管理器
  4. Java中BigDecimal用法
  5. OSEK network management
  6. 信号分析与处理(1)
  7. Kubernetes实践:使用k8s部署微服务应用
  8. 少量代码完成火山图绘制
  9. 使用傅里叶模态法分析闪耀光栅
  10. 【SQL基础】SQLzoo练习