quartz在集群环境下的配置方案
转载:quartz在集群环境下的最终解决方案
最近项目中使用了spring+Quartz定时任务、但是项目最近要集群部署、多个APP下如何利用Quartz 协调处理任务。
大家可以思考一下、现在有
A、B、C三个应用同时作为集群服务器对外统一提供服务、每个应用下各有一个Quartz、它们会按照既定的时间自动执行各自的任务。我们先不说实现什么功能,就说这样的架构其实有点像多线程。那多线程里就会存在“资源竞争”的问题,即可能产生脏读,脏写,由于三台
应用 里都有 Quartz,因此会存在重复处理 任务 的现象。
解决方案一:只在一台 应用 上装 Quartz,其它两台不装,这样集群就没有意义了。
解决方案二:使用其实Quartz自身可以实例化数据库的特性就可以解决问题
本方案优点:
1. 每台作为集群点的 应用上都可以布署 Quartz ;
2. Quartz 的 TASK ( 12 张表)实例化如数据库,基于数据库引擎及 High-Available 的策略(集群的一种策略)自动协调每个节点的 QUARTZ ,当任一一节点的 QUARTZ 非正常关闭或出错时,另几个节点的
QUARTZ 会自动启动;
3. 无需开发人员更改原已经实现的 QUARTZ ,使用 SPRING+ 类反射的机制对原有程序作切面重构;
解决方案:
1:去官网下载最新的 quartz 解压 在目录 docs\dbTables 下就会找到 tables_mysql.sql 文件、建立数据库Quartz 并导入数据库。
2:生成 quartz.properties 文件,把它放在工程的 src 目录下 修改配置文件如下:
3:重写 quartz 的 QuartzJobBean 类
原因是在使用 quartz+spring 把 quartz 的 task 实例化进入数据库时,会产生: serializable 的错误,原因在于:
这个 MethodInvokingJobDetailFactoryBean 类中的 methodInvoking 方法,是不支持序列化的,因此在把 QUARTZ 的 TASK 序列化进入数据库时就会抛错。网上有说把 SPRING 源码拿来,修改一下这个方案,然后再打包成
SPRING.jar 发布,这些都是不好的方法,是不安全的。
必须根据 QuartzJobBean 来重写一个自己的类 。
BootstrapJob.java:
引导Job,通过Spring容器获取任务的Job,根据注入的targetJob,该Job必须实现Job2接口
重写 MethodInvokingJobDetailFactoryBean类 方法如下:
QuartzDeleteQueAction 任务类、一定要实现接口job2、只做参考。
4:配置 applicationContext-job.xml:
此时手动 停掉那台运行 QUARTZ 过了 10分钟左右,另一个节点的 quartz 自动监测到了集群中运行着的 quartz 的
instance 已经 停掉 ,因此 quartz 集群会自动把任一台可用的 APP上启动起一个 quartz job 的任务。
至此 Quartz使用 集群策略已经ok,不用改原有代码,配置一下我们就可做到 Quartz的集群与自动错误冗余。
所需jar包:quartz-all-1.6.6.jar
spring.jar mysql-connector-java-3.1.11-bin.jar commons-pool-1.3.jar commons-logging-1.0.4.jar commons-dbcp-1.2.1.jar