最佳实践利用Quartz实现任务调度的集群Word格式文档下载.docx
《最佳实践利用Quartz实现任务调度的集群Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《最佳实践利用Quartz实现任务调度的集群Word格式文档下载.docx(11页珍藏版)》请在冰豆网上搜索。
目前集群只能工作在JDBC-Jobstore(JobStoreTX或者JobStoreCMT)方式下,从本质上来说,是使集群上的每一个节点通过共享同一个数据库来工作的(Quartz通过启动两个维护线程来维护数据库状态实现集群管理,一个是检测节点状态线程,一个是恢复任务线程)。
负载平衡是自动完成的,集群的每个节点会尽快触发任务。
当一个触发器的触发时间到达时,第一个节点将会获得任务(通过锁定),成为执行任务的节点。
故障切换的发生是在当一个节点正在执行一个或者多个任务失败的时候。
当一个节点失败了,其他的节点会检测到并且标识在失败节点上正在进行的数据库中的任务。
任何被标记为可恢复(任务详细信息的"
requestsrecovery"
属性)的任务都会被其他的节点重新执行。
没有标记可恢复的任务只会被释放出来,将会在下次相关触发器触发时执行
3.quartz集群步骤
3.1.创建Quartz数据库表
因为Quartz集群依赖于数据库,所以必须首先创建Quartz数据库表。
Quartz包括了所有被支持的数据库平台的SQL脚本。
在<
quartz_home>
/docs/dbTables目录下找到那些SQL脚本,这里的<
是解压Quartz分发包后的目录。
这里采用的Quartz1.8.5版本,总共12张表,不同版本,表个数可能不同。
数据库为oracle,用tables_oracle.sql创建数据库表。
3.2.配置数据库连接池
,这里使用Spring+C3p0
在系统的全局配置文件中新增如下信息,我这里的全局配置文件是:
config.properties
db.dialect=org.hibernate.dialect.Oracle9Dialect
db.driverClassName=oracle.jdbc.driver.OracleDriver
db.url=jdbc:
oracle:
thin:
@127.0.0.1:
1521:
feelview
db.username=feelviewdata
db.password=paic1234
TescronExpression1=00/1*?
**
其中:
TescronExpression1是定时器的crontab表达式(我这里配置的是每分钟跑一次),下面在配置CronTriggerBean的时候会使用到。
关于crontab表达式的配置这里不做介绍,在quartz的官方文档有详细介绍
<
!
—全局配置文件读入-->
<
beanid="
propertyConfigurer"
class="
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
>
<
propertyname="
locations"
<
list>
<
value>
classpath:
config.properties<
/value>
/list>
/property>
/bean>
—连接池配置-->
dataSource"
class="
com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="
close"
driverClass"
value="
${db.driverClassName}"
jdbcUrl"
${db.url}"
user"
${db.username}"
password"
${db.password}"
--连接池中保留的最小连接数。
-->
minPoolSize"
5<
--连接池中保留的最大连接数。
Default:
15-->
maxPoolSize"
30<
--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。
3-->
initialPoolSize"
10<
--最大空闲时间,60秒内未使用则连接被丢弃。
若为0则永不丢弃。
0-->
maxIdleTime"
60<
--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。
acquireIncrement"
--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。
但由于预缓存的statements属于单个connection而不是整个连接池。
所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。
0-->
maxStatements"
0<
--每60秒检查所有连接池中的空闲连接。
idleConnectionTestPeriod"
--定义在从数据库获取新连接失败后重复尝试的次数。
30-->
acquireRetryAttempts"
--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。
但是数据源仍有效
保留,并在下次调用getConnection()的时候继续尝试获取连接。
如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。
false-->
breakAfterAcquireFailure"
true<
--因性能消耗大请只在需要的时候使用它。
如果设为true那么在每个connection提交的时候都将校验其有效性。
建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。
false-->
testConnectionOnCheckout"
false<
/beans>
3.3.创建Job测试服务类
创建job接口,注意,因为Job需要持久化到数据库中,Job必须实现Serializable接口
publicinterfaceIJobextendsSerializable{
/**
*处理任务的核心函数
*
*@paramcxtSpring上下文
*/
voidexecuteInternal();
}
创建测试job
publicclassTestJobBus1implementsIJob{
privatestaticLoglog=LogFactory.getLog(TestJobBus1.class);
*TEST
publicvoidexecuteInternal(){
try{
System.out.println("
-------------TestJobBus1start-------------"
+InetAddress.getLocalHost());
}catch(UnknownHostExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
3.4.
配置Quartz使用集群
3.4.1.配置节点的quartz.properties文件
org.quartz.scheduler.instanceName=DefaultQuartzScheduler
org.quartz.scheduler.instanceId=AUTO
#org.quartz.scheduler.rmi.export=false
#org.quartz.scheduler.rmi.proxy=false
#org.quartz.scheduler.wrapJobExecutionInUserTransaction=false
#============================================================================
#ConfigureThreadPool
#org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#org.quartz.threadPool.threadCount=10
#org.quartz.threadPool.threadPriority=5
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
#ConfigureJobStore
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.tablePrefix=QRTZ_
#org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=15000
org.quartz.scheduler.instanceName属性可为任何值,用在JDBCJobStore中来唯一标识实例,但是所有集群节点中必须相同。
org.quartz.scheduler.instanceId 属性为AUTO即可,基于主机名和时间戳来产生实例ID。
org.quartz.jobStore.class属性为JobStoreTX,将任务持久化到数据中。
因为集群中节点依赖于数据库来传播Scheduler实例的状态,你只能在使用JDBCJobStore时应用Quartz集群。
这意味着你必须使用JobStoreTX或是JobStoreCMT作为Job存储;
你不能在集群中使用RAMJobStore。
org.quartz.jobStore.isClustered属性为true,你就告诉了Scheduler实例要它参与到一个集群当中。
这一属性会贯穿于调度框架的始终,用于修改集群环境中操作的默认行为。
org.quartz.jobStore.clusterCheckinInterval属性定义了Scheduler实例检入到数据库中的频率(单位:
毫秒)。
Scheduler检查是否其他的实例到了它们应当检入的时候未检入;
这能指出一个失败的Scheduler实例,且当前Scheduler会以此来接管任何执行失败并可恢复的Job。
通过检入操作,Scheduler也会更新自身的状态记录。
clusterChedkinInterval越小,Scheduler节点检查失败的Scheduler实例就越频繁。
默认值是15000(即15秒)。
3.4.2.配置applicationContext-quartz.xml文件
?
xmlversion="
1.0"
encoding="
UTF-8"
DOCTYPEbeansPUBLIC"
-//SPRING//DTDBEAN//EN"
"
http:
//www.springframework.org/dtd/spring-beans.dtd"
beans>
beanclass="
org.springframework.scheduling.quartz.SchedulerFactoryBean"
ref="
/>
configLocation"
quartz.properties"
triggers"
refbean="
testJob1"
/>
startupDelay"
2"
applicationContextSchedulerContextKey"
applicationContext"
--********************************************testJob1********************************************-->
org.springframework.scheduling.quartz.CronTriggerBean"
jobDetail"
testJobDetail1"
cronExpression"
${TescronExpression1}"
com.grgbanking.view.scheduling.MethodInvokingJobDetailFactoryBean"
concurrent"
false"
shouldRecover"
true"
targetObject"
testJobBus1"
targetMethod"
executeInternal"
com.grgbanking.view.scheduling.TestJobBus1"
dataSource:
项目中用到的数据源,里面包含了quartz用到的12张数据库表;
applicationContextSchedulerContextKey:
是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类中把spring上下文以key/value的方式存放在了quartz的上下文中了,可以用applicationContextSchedulerContextKey所定义的key得到对应的spring上下文;
configLocation:
用于指明quartz的配置文件的位置
关于Job配置,这里有两点需要注意
MethodInvokingJobDetailFactoryBean
在这里使用网上牛人修改后的frameworkx.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean(此案例我改包名为:
com.grgbanking.view.scheduling),此类在网上可以下载,直接使用org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean会报java.io.NotSerializableException异常。
shouldRecover
shouldRecover属性必须设置为true,当Quartz服务被中止后,再次启动或集群中其他机器接手任务时会尝试恢复执行之前未完成的所有任务。
3.4.3.配置web.xml文件
初始化spring信息
web-appversion="
2.4"
xmlns="
xmlns:
xsi="
//www.w3.org/2001/XMLSchema-instance"
xsi:
schemaLocation="
welcome-file-list>
welcome-file>
index.jsp<
/welcome-file>
/welcome-file-list>
context-param>
param-name>
contextConfigLocation<
/param-name>
param-value>
/WEB-INF/applicationContext.xml,/WEB-INF/data.xml,/WEB-INF/applicationContext-quartz.xml<
/param-value>
/context-param>
listener>
listener-class>
org.springframework.web.context.ContextLoaderListener<
/listener-class>
/listener>
/web-app>
4.运行Quartz集群
通过tomcat集群测试定时器执行情况,由于我两个节点的quartz.properties配置的是一样,这样两个节点会交替执行。
现在定时器TestJobBus1本来是每1分钟执行一次并打印:
“"
”与执行时间。
通过下面的打印可以看出两个节点是交替执行的。
节点1
节点2
5.关于Quartz
Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器、任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述:
●Job:
是一个接口,只有一个方法voidexecute(JobExecutionContextcontext),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。
Job运行时的信息保存在JobDataM