⏲️定时任务(3):Quartz 集群
00 分钟
2024-7-25
2024-7-26
type
status
date
Jul 26, 2024 04:04 AM
slug
summary
category
tags
password
icon

概述

Quartz单机方案使用的存储器是Memory内存,而Quartz集群方案使用的存储器是 JDBC 存储器 JobStoreTX ,使用 MySQL 作为数据库。
两种方案的对比如下:
类型
优点
缺点
RAMJobStore
不要外部数据库,配置容易,运行速度快
因为调度程序信息是存储在被分配给JVM的内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。另外因为存储到JVM内存里面,所以可以存储多少个Job和Trigger将会受到限制
JDBC作业存储
支持集群,因为所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应用服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启而导致执行失败的任务
运行速度的快慢取决与连接数据库的快慢
Quartz集群基于数据库锁的同步,操作流程如下图所示:
notion image

Quartz 集群

引入Maven依赖

DemoJob

DemoJob01

  • 相比DemoJob01来说,在类上添加了 Quartz 的 @DisallowConcurrentExecution 注解,保证相同 JobDetail 在多个 JVM 进程中,有且仅有一个节点在执行。
注意:
  1. 不是以 Quartz Job 为维度,保证在多个 JVM 进程中,有且仅有一个节点在执行,而是以 JobDetail 为维度。虽然说,绝大多数情况下,我们会保证一个 Job 和 JobDetail 是一一对应。所以,一定要搞清楚这个概念。实在有点懵逼,保证一个 Job 和 JobDetail 是一一对应就对了。
  1. 而 JobDetail 的唯一标识是 JobKey ,使用 name + group 两个属性。一般情况下,我们只需要设置 name 即可,而 Quartz 会默认 group = DEFAULT 。
  1. 不过这里还有一点要补充,也是需要注意的,在 Quartz 中,相同 Scheduler 名字的节点,形成一个 Quartz 集群。在下文中,我们可以通过 spring.quartz.scheduler-name 配置项,设置 Scheduler 的名字。
【重要】为什么要说这个呢?因为我们要完善一下上面的说法:通过在 Job 实现类上添加 @DisallowConcurrentExecution 注解,实现在相同 Quartz Scheduler 集群中,相同 JobKey 的 JobDetail ,保证在多个 JVM 进程中,有且仅有一个节点在执行。

DemoJob02

相关配置

配置文件

  • 在 spring.datasource 配置项下,用于创建多个数据源的配置。
    • user 配置,连接quartz-jdbc-user 库。目的是,为了模拟我们一般项目,使用到的业务数据库
    • quartz 配置,连接quartz-jdbc-quartz 库。目的是,Quartz 会使用单独的数据库。如果我们有多个项目需要使用到 Quartz 数据库的话,可以统一使用一个,但是要注意配置 spring.quartz.scheduler-name 设置不同的 Scheduler 名字,形成不同的 Quartz 集群。
  • 在 spring.quartz 配置项下:
    • scheduler-name 配置,Scheduler 名字。
    • job-store-type 配置,设置了使用 "jdbc" 的 Job 存储器。
    • properties.org.quartz.jobStore 配置,增加了 JobStore 相关配置。重点是,通过 dataSource 配置项,设置了使用名字为 "quartzDataSource" 的 DataSource 为数据源。在 DataSourceConfiguration 中,我们会使用 spring.datasource.quartz 配置,来创建该数据源。
    • jdbc 配置项,虽然名字叫这个,主要是为了设置使用 SQL 初始化 Quartz 表结构。这里,我们设置 initialize-schema = never ,我们手动创建表结构。

DataSourceConfiguration

  • 基于 spring.datasource.user 配置项,创建了名字为 "userDataSource" 的 DataSource Bean 。并且,在其上我们添加了 @Primay 注解,表示其是数据源。
  • 基于 spring.datasource.quartz 配置项,创建了名字为 "quartzDataSource" 的 DataSource Bean 。并且,在其上我们添加了 @QuartzDataSource 注解,表示其是 Quartz 的数据源。

初始化 Quartz 表结构

在 Quartz Download 地址,下载对应版本的发布包。解压后,我们可以在 src/org/quartz/impl/jdbcjobstore/ 目录,看到各种数据库的 Quartz 表结构的初始化脚本。这里,因为我们使用 MySQL ,所以使用 tables_mysql_innodb.sql 脚本。
在数据库中执行该脚本,完成初始化 Quartz 表结构。如下图所示:
notion image
关于每个 Quartz 表结构的说明,可以看看 Quartz 框架——JobStore 数据库表字段详解
我们会发现,每个表都有一个 SCHED_NAME 字段,Quartz Scheduler 名字。这样,实现每个 Quartz 集群,数据层面的拆分。

定时任务配置

完成上述的工作之后,我们需要配置 Quartz 的定时任务。目前,有两种方式:
  1. Bean 自动设置
  1. Scheduler 手动设置

Bean 自动设置

在 Quartz 调度器启动的时候,会根据该配置,自动调用如下方法
  • Scheduler#addJob(JobDetail jobDetail, boolean replace) 方法,将 JobDetail 持久化到数据库。
  • Scheduler#scheduleJob(Trigger trigger) 方法,将 Trigger 持久化到数据库。

Scheduler 手动设置

  • 在每个单元测试方法的最后,调用 Scheduler#scheduleJob(JobDetail jobDetail, Trigger trigger) 方法,将 JobDetail 和 Trigger 持久化到数据库。
  • 如果想要覆盖数据库中的 Quartz 定时任务的配置,可以调用 Scheduler#scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) 方法(也就是scheduler.scheduleJob(jobDetail, Sets.newSet(trigger), true);),传入 replace = true 进行覆盖配置。

测试

日志输入

启动Application,观察日志的输出

数据库的内容

quartz-jdbc-quartz数据库中,表qrtz_job_details的内容如下:
quartz-jdbc-quartz数据库中,表qrtz_cron_triggers的内容如下:
quartz-jdbc-quartz数据库中,表qrtz_triggers的内容如下:

参考

 

评论
Loading...