现在公司居然用了Quartz定时任务框架,今天我们就来盘它!!!!
Quartz 是一个功能强大的开源任务调度框架,支持任务持久化、集群部署、分布式调度等特性。下面从架构、核心组件、运行流程和 JDBC 持久化机制四个方面详细分析其原理:
一、Quartz 核心架构
┌───────────────────────────────────────────────────────────┐
│ 客户端应用 │
└───────────────────────────┬───────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────┐
│ Quartz Scheduler │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ JobStore (JDBC) │ │ ThreadPool │ │ Scheduler │ │
│ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────┐ │ │
│ │ │ 数据库表结构 │ │ │ │ 工作线程池 │ │ │ │ 调度引擎│ │ │
│ │ └─────────────┘ │ │ └─────────────┘ │ │ └─────────┘ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
└───────────────────────────┬───────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────┐
│ JDBC 持久化存储 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ QRTZ_JOBS │ │ QRTZ_TRIGGERS │ │ QRTZ_CALENDARS │ │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ QRTZ_JOB_DETAILS │ │ QRTZ_SIMPLE_TRIGGERS │ │ ... │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────────────────────────────────────────┘
二、核心组件功能
-
Scheduler(调度器)
- 核心入口,负责任务的注册、启动、暂停、删除等操作。
- 通过
SchedulerFactory
创建,支持集群模式(ClusterManager
负责协调节点)。
-
Job(任务)
- 实现
org.quartz.Job
接口的类,定义具体执行逻辑(execute()
方法)。 - 分为有状态(
StatefulJob
)和无状态两种,有状态任务会保存运行时数据。
- 实现
-
Trigger(触发器)
- 定义任务执行的时间规则,支持多种类型:
SimpleTrigger
:固定频率/次数触发。CronTrigger
:基于 Cron 表达式触发。CalendarIntervalTrigger
:基于日历间隔(如每月1号)。
- 包含优先级、错过触发策略(Misfire Instruction)等配置。
- 定义任务执行的时间规则,支持多种类型:
-
JobStore(任务存储)
- 负责存储任务和触发器的状态信息,支持内存存储(
RAMJobStore
)和持久化存储(JDBCJobStore
)。 - 持久化实现依赖数据库表结构(如
QRTZ_JOB_DETAILS
、QRTZ_TRIGGERS
)。
- 负责存储任务和触发器的状态信息,支持内存存储(
-
ThreadPool(线程池)
- 执行任务的工作线程池,默认实现为
SimpleThreadPool
。 - 配置参数:
threadCount
(线程数)、threadPriority
(线程优先级)等。
- 执行任务的工作线程池,默认实现为
三、JDBC 持久化机制
Quartz 通过 JDBCJobStore
实现任务状态持久化,核心逻辑:
1. 数据库表结构(部分核心表)
表名 | 作用 |
---|---|
QRTZ_JOB_DETAILS | 存储 Job 定义(类名、描述、是否持久化等) |
QRTZ_TRIGGERS | 存储触发器基本信息(关联 Job、触发类型、状态等) |
QRTZ_CRON_TRIGGERS | 存储 Cron 触发器的表达式和时区信息 |
QRTZ_SIMPLE_TRIGGERS | 存储 Simple 触发器的重复次数、间隔等信息 |
QRTZ_FIRED_TRIGGERS | 存储正在执行或已完成的触发器状态(锁机制、执行时间等) |
QRTZ_SCHEDULER_STATE | 存储调度器实例状态(心跳信息、集群节点状态) |
QRTZ_LOCKS | 实现分布式锁(用于集群环境下的任务调度协调) |
2. 数据持久化流程
-
任务注册:
scheduler.scheduleJob(jobDetail, trigger)
会将 Job 和 Trigger 信息写入QRTZ_JOB_DETAILS
和QRTZ_TRIGGERS
表。 -
状态变更:
触发器状态(WAITING
、ACQUIRED
、EXECUTING
等)在任务生命周期中不断更新,写入QRTZ_TRIGGERS
和QRTZ_FIRED_TRIGGERS
表。 -
调度器状态:
集群模式下,每个调度器实例定期更新QRTZ_SCHEDULER_STATE
表的心跳信息,用于故障检测和负载均衡。
3. 锁机制(集群环境)
Quartz 通过 QRTZ_LOCKS
表实现分布式锁,常见锁类型:
TRIGGER_ACCESS
:保证同一触发器在集群中只被一个节点执行。JOB_ACCESS
:控制对 Job 数据的访问。STATE_ACCESS
:协调调度器状态。
四、运行流程详解
1. 初始化阶段
// 创建调度器实例(从配置文件读取参数)
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
// 配置 JDBCJobStore
Properties props = new Properties();
props.setProperty("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
props.setProperty("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
props.setProperty("org.quartz.jobStore.dataSource", "myDS");
props.setProperty("org.quartz.dataSource.myDS.driver", "com.mysql.jdbc.Driver");
props.setProperty("org.quartz.dataSource.myDS.URL", "jdbc:mysql://localhost/quartz");
// 其他配置...
2. 任务注册与调度
// 定义 Job
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("job1", "group1")
.build();
// 定义触发器(Cron 表达式)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // 每5秒执行一次
.build();
// 注册任务到调度器(数据写入数据库)
scheduler.scheduleJob(job, trigger);
scheduler.start(); // 启动调度器
3. 触发与执行流程
调度器线程轮询触发器状态(从 QRTZ_TRIGGERS 表)
↓
发现待触发的触发器(状态=WAITING 且 next_fire_time <= 当前时间)
↓
获取 TRIGGER_ACCESS 锁(更新 QRTZ_LOCKS 表)
↓
更新触发器状态为 ACQUIRED(更新 QRTZ_TRIGGERS 表)
↓
从线程池分配工作线程执行任务
↓
执行 Job.execute() 方法
↓
任务完成后更新触发器状态(如 RELEASED、COMPLETED)
↓
释放 TRIGGER_ACCESS 锁
4. 集群环境下的协调
- 故障转移:若节点宕机,其他节点通过
QRTZ_SCHEDULER_STATE
表检测到心跳超时,接管未完成的任务。 - 负载均衡:多个节点通过竞争锁(
QRTZ_LOCKS
)决定由谁执行任务,避免重复调度。
五、关键配置参数(JDBC 持久化)
# 存储方式:JDBC 事务模式
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# 数据库方言(根据数据库类型选择)
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 数据源配置
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost/quartz
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = quartz
org.quartz.dataSource.myDS.maxConnections = 10
# 表前缀(多应用共享数据库时使用)
org.quartz.jobStore.tablePrefix = QRTZ_
# 集群模式开关
org.quartz.jobStore.isClustered = true
org.quartz.scheduler.instanceId = AUTO # 自动生成实例ID
org.quartz.jobStore.clusterCheckinInterval = 20000 # 集群检查间隔(毫秒)
六、优缺点分析
优点
- 功能全面:支持各种复杂的调度需求(Cron、集群、持久化)。
- 扩展性强:可自定义 JobStore、ThreadPool 等组件。
- 成熟稳定:社区活跃,广泛应用于企业级系统。
缺点
- 配置复杂:尤其是集群和持久化配置。
- 性能开销:依赖数据库操作,频繁调度时可能成为瓶颈。
- 学习曲线:核心概念(Job、Trigger、JobStore)较多,入门门槛较高。
Quartz 通过 JDBC 持久化实现了任务状态的可靠存储和集群环境下的高可用调度,适合对任务可靠性要求高、需要跨应用共享任务配置的场景。但需注意数据库性能优化和集群配置的复杂性。
如果用数据库持久化的化,就要注意了,我们数据库经常出现IO Error 的问题,导致定时任务在维护任务状态的时候出现问题,从而任务一直就中断了。卡在了立即执行的状态!