Quartz在集群环境下的最终解决方案

集群环境下,大家会碰到一直困扰的问题,即多个 APP 下如何用 quartz 协调处理自动化 JOB 。

大家想象一下,现在有 A , B , C3 台机器同时作为集群服务器对外统一提供 SERVICE :

A , B , C 3 台机器上各有一个 QUARTZ ,他们会按照即定的 SCHEDULE 自动执行各自的任务。

我们先不说实现什么功能,就说这样的架构其实有点像多线程。

那多线程里就会存在“资源竞争”的问题,即可能产生脏读,脏写,由于三台 APP SERVER 里都有 QUARTZ ,因此会存在重复处理 TASK 的现象。

一般外面的解决方案是只在一台 APP 上装 QUARTZ ,其它两台不装,这样集群就形同虚设了;

另一种解决方案是动代码,这样就要影响到原来已经写好的 QUARTZ JOB 的代码了,这对程序开发人员来说比较痛苦;

本人仔细看了一下 Spring 的结构和 QUARTZ 的文档,结合 Quartz 自身可以实例化进数据的特性找到了相关的解决方案。

本方案优点:

1.       每台作为集群点的 APP SERVER 上都可以布署 QUARTZ ;

2.       QUARTZ 的 TASK ( 12 张表)实例化如数据库,基于数据库引擎及 High-Available 的策略(集群的一种策略)自动协调每个节点的 QUARTZ ,当任一一节点的 QUARTZ 非正常关闭或出错时,另几个节点的 QUARTZ 会自动启动;

3.       无需开发人员更改原已经实现的 QUARTZ ,使用 SPRING+ 类反射的机制对原有程序作切面重构;

本人也事先搜索了一些资料,发觉所有目前在 GOOGLE 上或者在各大论坛里提供的解决方案,要么是只解决了一部分,要么是错误的,要么是版本太老,要么就是完全抄别人的。

尤其是在使用 QUARTZ+SPRING 对数据库对象作实例化时会抛错(源于 SPRING 的一个 BUG ),目前网上的解决方案全部是错的或者干脆没说,本人在此方案中也会提出如何解决。


解决方案:

1.       把 QUARTZ 的 TASK 实例化进数据库, QUARTZ 只有实例化进入数据库后才能做集群,外面的解决方案说实例化在内存里全部是错的,把quartz-1.8.4/docs/dbTables/tables_Oracle.sql 在 ORACLE9I2 及以上版本中执行一下会生成 12 张表;

2.       生成 quartz.properties 文件,把它放在工程的 src 目录下,使其能够被编译时纳入 class path 。

一般我们的开发人员都喜欢使用 SPRING+QUARTZ ,因此这个 quartz.properties 都不用怎么去写,但是在集群方案中 quartz.properties 必写,如果不写 quartz 会调用自身 jar 包中的 quartz.properties 作为默认属性文件,同时修改 quartz.xml 文件。

Quartz.xml 文件的内容 :

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd ">

<beans>

<bean lazy-init="false" autowire="no"

>

<property value="classpath:quartz.properties" />

<property>

<list>

<ref bean="cronTrigger" />

</list>

</property>

<!— 就是下面这句,因为该 bean 只能使用类反射来重构

<property value="applicationContext" />          

</bean>

quartz.properties 文件的内容:

org.quartz.scheduler.instanceName = mapScheduler  

org.quartz.scheduler.instanceId = AUTO 

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX 

org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate 

org.quartz.jobStore.dataSource = myXADS 

org.quartz.jobStore.tablePrefix = QRTZ_ 

org.quartz.jobStore.isClustered = true 

org.quartz.dataSource.myXADS.jndiURL=jdbc/TestQuartzDS

org.quartz.dataSource.myXADS.jndiAlwaysLookup = DB_JNDI_ALWAYS_LOOKUP 

org.quartz.dataSource.myXADS.java.naming.factory.initial = weblogic.jndi.WLInitialContextFactory 

org.quartz.dataSource.myXADS.java.naming.provider.url = t3://localhost:7020 

org.quartz.dataSource.myXADS.java.naming.security.principal = weblogic 

org.quartz.dataSource.myXADS.java.naming.security.credentials = weblogic 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/320e2549de492e9680bb4146ed1818e3.html