Quartz 是什么?
Quartz 是一个任务调度框架(库),有些定时任务需要在指定时间内执行或者周期性执行某个任务时需要用到任务调度框架。
Quartz 是非常灵活的,包含多个使用范例(可以单独或一起使用,以实现期望的行为)。
Quartz 是非常轻量级的,只需要非常少的配置。
Quartz 具有容错机制,并且可以在重启服务的时候持久化定时任务。
Quartz 不是什么?
Quartz 不是一个任务队列。
Quartz 不是一个网格计算引擎。
Quartz 不是一个提供给业务人员的执行服务,而是一个代码库,很容易集成到应用程序中。
从组件角度来看 Quartz 是什么?
Quartz 是一个很轻量级的 java 库,几乎包含了所有定时的功能。主要接口是 Schedule,提供了一些简单的操作:安排任务或取消任务,启动或者停止任务。
如果要使用 Quartz,应该实现 Job
接口,包含了一个 execute()
方法。
如果想在一个任务执行时间到了的时候通知你,应该实现 TriggerListener
或者 JobListener
接口。
为什么不简单的使用 java.util.Timer?
从 JDK1.3 开始,通过 java.util.Timer
和 java.util.TimerTask
可以实现定时器。为什么要使用 Quartz 而不是使用 Java 中的这些标准功能呢?
- Timers 没有持久化机制.
- Timers 不灵活,只可以设置开始时间和重复间隔,不是基于时间、日期、天等(秒、分、时)的
- Timers 不能利用线程池,一个 Timer 一个线程
- Timers 没有真正的管理计划
Quartz 可以运行多少任务?
取决于使用情况。JobStore 扮演着一个重要的因素。基于 RAM 的 JobStore 比基于 JDBC 的 JobStore 更快近乎100倍。JDBC JobStore 速度几乎完全取决于数据库的连接速度,使用的数据库系统,以及数据库运行的硬件设备。基于 RAM 的 JobStore 存储的 Job 和 Triggers 也是有限制的,可使用的空间肯定比数据库的硬盘空间要小。
关于 Job 的一些问题
如何控制 Job 的实例?
查看 org.quartz.spi.JobFactory
和 org.quartz.Scheduler.setJobFactory(..)
的方法。
当一个 Job 完成并移除之后,还能保存吗?
设置属性:JobDetail.setDurability(true);
当 Job 不再有 Trigger 引用时,Quartz 不需要删除 Job。
如何控制一个 Job 并发执行?
实现 StatefulJob。
如何停止一个正在执行的 Job?
查看 org.quartz.InterruptableJob
接口和 Scheduler.interrupt(String, String)
方法。
关于 Trigger 的一些问题
怎么执行任务链(工作流)?
目前还没有直接的方式通过 Quartz 链式触发任务。
方法一:
使用监听器(TriggerListener
,JobListener
或者 SchedulerListener
),可以通知到某个工作完成,然后可以开始另一个任务。这种方式有一点复杂,必须告知监听器哪个任务是接着哪个任务的。可以查看 org.quartz.listeners.JobChainingJobListener
已经具有一些这样的功能了。
方法二:
创建一个 Job,JobDataMap
包含下一个 Job 的名字,当这一个 Job 执行完毕再执行下一个任务。
大多数的做法是创建一个基类(通常是抽象类或接口)作为 Job,并拥有获得 Job 名称的方法,使用预定义的 Key 从 JobDataMap
进行分组。抽象类实现 execute()
方法委托模板方法例如 doWork()
去执行,包含了调度后续作业的代码。之后子类要做的只是简单的扩展这个类,包括做自己应该做的工作。
为什么 trigger 没有执行?
常见的原因可能是没有调用 Scheduler.start()
方法,这个方法告诉调度程序启动触发器。还有一种可能是 trigger 或者 trigger group 被暂停了。
关于 JDBCJobStore 的一些问题
怎么提升 JDBC-JobStore 的性能?
- 使用更快更好的网络
- 更好的机器
- 更好的 RDBMS
一种简单但有效的方式:在 Quartz 表建立索引
最重要的索引的 TRIGGER 表的 next_fire_time、state 字段。
create index idx_qrtz_t_next_fire_time on qrtz_triggers(NEXT_FIRE_TIME);
create index idx_qrtz_t_state on qrtz_triggers(TRIGGER_STATE);
create index idx_qrtz_t_nf_st on qrtz_triggers(TRIGGER_STATE,NEXT_FIRE_TIME);
create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(TRIGGER_NAME);
create index idx_qrtz_ft_trig_group on qrtz_fired_triggers(TRIGGER_GROUP);
create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(TRIGGER_NAME);
create index idx_qrtz_ft_trig_n_g on qrtz_fired_triggers(TRIGGER_NAME,TRIGGER_GROUP);
create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(INSTANCE_NAME);
create index idx_qrtz_ft_job_name on qrtz_fired_triggers(JOB_NAME);
create index idx_qrtz_ft_job_group on qrtz_fired_triggers(JOB_GROUP);
create index idx_qrtz_t_next_fire_time_misfire on qrtz_triggers(MISFIRE_INSTR,NEXT_FIRE_TIME);
create index idx_qrtz_t_nf_st_misfire on qrtz_triggers(MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
create index idx_qrtz_t_nf_st_misfire_grp on qrtz_triggers(MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
Quartz 集群能力
集群功能最适合于长时间运行或密集的工作(在多个节点上分配工作负载),如果需要扩展到支持成千上万的短运行(例如1秒)的工作,考虑工作集分割使用多个不同的调度器。
Quartz 具有可扩展和高可用性功能。可以在 Quartz 配置资料中找到答案:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/configuration/