Quartz特性及其集群特性

Feature

作业调度

   当满足指定的触发器条件时,作业会被调度。触发器可以设置成在一天的特定时间(到毫秒)
在一周的某几天
在每月的某一天
在一年中的某些日子
特定时间除外的时间(如商业节假日除外)not on certain days listed within a registered Calendar (such as business holidays)
重复特定次数
重复进行,直到一个特定时间/日期
无限重复
重复一个延迟间隔

为了方便的在调度器中调度作业,作业和触发器都可以被命名或者组织到多个命名的组中。一个作业只能加入到调度器一次,但是可以跟多个触发器关联。



 作业持久化

Quartz设计了一个JobStore的接口,可以通过不同实现方式实现持久化作业。

通过JDBSJobStore,所有的作业和触发器可以呗设置为"非易失的",进而存储在关系数据库中。

通过RAMJobStore,所有的作业和触发器可以被存储在内存中,这种情况下并不会实现存储话





The key interfaces of the Quartz API are:

Scheduler - the main API for interacting with the Scheduler.

Job - an interface to be implemented by components that you want the Scheduler to execute.

JobDetail - used to define instances of Jobs.

Trigger - a component that defines the schedule upon which a given Job will be executed.

JobBuilder - used to define/build JobDetail instances, which define instances of Jobs.TriggerBuilder - used to define/build Trigger instances.



Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞。
1.在Spring中这时需要设置concurrent的值为false, 禁止并发执行。

?
1
  <property name= "concurrent" value= "true" />

2.当不使用spring的时候就需要在Job的实现类上加@DisallowConcurrentExecution的注释
@DisallowConcurrentExecution 禁止并发执行多个相同定义的JobDetail, 这个注解是加在Job类上的, 但意思并不是不能同时执行多个Job, 而是不能并发执行同一个Job Definition(由JobDetail定义), 但是可以同时执行多个不同的JobDetail, 举例说明,我们有一个Job类,叫做SayHelloJob, 并在这个Job上加了这个注解, 然后在这个Job上定义了很多个JobDetail, 如sayHelloToJoeJobDetail, sayHelloToMikeJobDetail, 那么当scheduler启动时, 不会并发执行多个sayHelloToJoeJobDetail或者sayHelloToMikeJobDetail, 但可以同时执行sayHelloToJoeJobDetail跟sayHelloToMikeJobDetail

@PersistJobDataAfterExecution 同样, 也是加在Job上,表示当正常执行完Job后, JobDataMap中的数据应该被改动, 以被下一次调用时用。当使用@PersistJobDataAfterExecution 注解时, 为了避免并发时, 存储数据造成混乱, 强烈建议把@DisallowConcurrentExecution注解也加上。

 

 

@DisallowConcurrentExecution

此标记用在实现Job的类上面,意思是不允许并发执行,按照我之前的理解是 不允许调度框架在同一时刻调用Job类,后来经过测试发现并不是这样,而是Job(任务)的执行时间[比如需要10秒]大于任务的时间间隔 [Interval(5秒)],那么默认情况下,调度框架为了能让 任务按照我们预定的时间间隔执行,会马上启用新的线程执行任务。否则的话会等待任务执行完毕以后 再重新执行!(这样会导致任务的执行不是按照我们预先定义的时间间隔执行)

测试代码,这是官方提供的例子。设定的时间间隔为3秒,但job执行时间是5秒,设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行,否则会在3秒时再启用新的线程执行





集群特性

Clustering
Clustering currently works with the JDBC-Jobstore (JobStoreTX or JobStoreCMT) and the TerracottaJobStore. Features include load-balancing and job fail-over (if the JobDetail's "request recovery" flag is set to true).
Clustering With JobStoreTX or JobStoreCMT
Enable clustering by setting the org.quartz.jobStore.isClustered property to true. Each instance in the cluster should use the same copy of the quartz.properties file. Exceptions of this would be to use properties files that are identical, with the following allowable exceptions: Different thread pool size, and different value for the org.quartz.scheduler.instanceId property. Each node in the cluster  must have a unique instanceId, which is easily done (without needing different properties files) by placing "AUTO" as the value of this property.
Important: 
Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service or daemon that runs very regularly (the clocks must be within a second of each other). See http://www.boulder.nist.gov/timefreq/service/its.htm if you are unfamiliar with how to do this.
Important: 
Never fire-up a non-clustered instance against the same set of tables that any other instance is running against. You may get serious data corruption, and will experience erratic behavior.
Only one node will fire the job for each firing. For example, if the job has a repeating trigger that tells it to fire every 10 seconds, then at 12:00:00 exactly one node will run the job, and at 12:00:10 exactly one node will run the job, etc. It won't necessarily be the same node each time - it will more or less be random which node runs it. The load balancing mechanism is near-random for busy schedulers (lots of triggers) but favors the same node that just was just active for non-busy (e.g. one or two triggers) schedulers.
Clustering With TerracottaJobStore
Simply configure the scheduler to use TerracottaJobStore as described in  TerracottaJobStore, and your scheduler will be set for clustering.
You may also want to consider implications of how you setup your Terracotta server, particularly configuration options that turn on features such as persistence, and running an array of Terracotta servers for HA.
The licensed edition of TerracottaJobStore provides advanced Quartz Where features, that allow for intelligent targeting of jobs to appropriate cluster nodes.



2、Quartz集群原理

2.1 Quartz 集群架构

  一个Quartz集群中的每个节点是一个独立的Quartz应用,它又管理着其他的节点。这就意味着你必须对每个节点分别启动或停止。Quartz集群中,独立的Quartz节点并不与另一其的节点或是管理节点通信,而是通过相同的数据库表来感知到另一Quartz应用的,如图2.1所示。

图2.1 Quartz集群架构

2.2 Quartz集群相关数据库表

  因为Quartz集群依赖于数据库,所以必须首先创建Quartz数据库表,Quartz发布包中包括了所有被支持的数据库平台的SQL脚本。这些SQL脚本存放于<quartz_home>/docs/dbTables 目录下。这里采用的Quartz 1.8.4版本,总共12张表,不同版本,表个数可能不同。数据库为mysql,用tables_mysql.sql创建数据库表。全部表如图2.2所示,对这些表的简要介绍如图2.3所示。

 

图2.2 Quartz 1.8.4在mysql数据库中生成的表

图2.3 Quartz数据表简介

2.2.1 调度器状态表(QRTZ_SCHEDULER_STATE)

  说明:集群中节点实例信息,Quartz定时读取该表的信息判断集群中每个实例的当前状态。

  instance_name:配置文件中org.quartz.scheduler.instanceId配置的名字,如果设置为AUTO,quartz会根据物理机名和当前时间产生一个名字。

  last_checkin_time:上次检入时间

  checkin_interval:检入间隔时间

2.2.2 触发器与任务关联表(qrtz_fired_triggers)

  存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息。

2.2.3 触发器信息表(qrtz_triggers)

  trigger_name:trigger的名字,该名字用户自己可以随意定制,无强行要求

  trigger_group:trigger所属组的名字,该名字用户自己随意定制,无强行要求

  job_name:qrtz_job_details表job_name的外键

  job_group:qrtz_job_details表job_group的外键

  trigger_state:当前trigger状态设置为ACQUIRED,如果设为WAITING,则job不会触发

  trigger_cron:触发器类型,使用cron表达式

2.2.4 任务详细信息表(qrtz_job_details)

  说明:保存job详细信息,该表需要用户根据实际情况初始化

  job_name:集群中job的名字,该名字用户自己可以随意定制,无强行要求。

  job_group:集群中job的所属组的名字,该名字用户自己随意定制,无强行要求。

  job_class_name:集群中job实现类的完全包名,quartz就是根据这个路径到classpath找到该job类的。

  is_durable:是否持久化,把该属性设置为1,quartz会把job持久化到数据库中

  job_data:一个blob字段,存放持久化job对象。

2.2.5权限信息表(qrtz_locks)

  说明:tables_oracle.sql里有相应的dml初始化,如图2.4所示。

图2.4 Quartz权限信息表中的初始化信息

2.3 Quartz Scheduler在集群中的启动流程

  Quartz Scheduler自身是察觉不到被集群的,只有配置给Scheduler的JDBC JobStore才知道。当Quartz Scheduler启动时,它调用JobStore的schedulerStarted()方法,它告诉JobStore Scheduler已经启动了。schedulerStarted() 方法是在JobStoreSupport类中实现的。JobStoreSupport类会根据quartz.properties文件中的设置来确定Scheduler实例是否参与到集群中。假如配置了集群,一个新的ClusterManager类的实例就被创建、初始化并启动。ClusterManager是在JobStoreSupport类中的一个内嵌类,继承了java.lang.Thread,它会定期运行,并对Scheduler实例执行检入的功能。Scheduler也要查看是否有任何一个别的集群节点失败了。检入操作执行周期在quartz.properties中配置。

2.4 侦测失败的Scheduler节点

  当一个Scheduler实例执行检入时,它会查看是否有其他的Scheduler实例在到达他们所预期的时间还未检入。这是通过检查SCHEDULER_STATE表中Scheduler记录在LAST_CHEDK_TIME列的值是否早于org.quartz.jobStore.clusterCheckinInterval来确定的。如果一个或多个节点到了预定时间还没有检入,那么运行中的Scheduler就假定它(们) 失败了。

2.5 从故障实例中恢复Job

  当一个Sheduler实例在执行某个Job时失败了,有可能由另一正常工作的Scheduler实例接过这个Job重新运行。要实现这种行为,配置给JobDetail对象的Job可恢复属性必须设置为true(job.setRequestsRecovery(true))。如果可恢复属性被设置为false(默认为false),当某个Scheduler在运行该job失败时,它将不会重新运行;而是由另一个Scheduler实例在下一次触发时间触发。Scheduler实例出现故障后多快能被侦测到取决于每个Scheduler的检入间隔(即2.3中提到的org.quartz.jobStore.clusterCheckinInterval)。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值