概述
虽然单个Quartz实例能给予你很好的Job调度能力,但它不能满足典型的企业需求,如可伸缩性、高可靠性满足。假如你需要故障转移的能力并能运行日益增多的 Job,Quartz集群势必成为你应用的一部分了。使用 Quartz 的集群能力可以更好的支持你的业务需求,并且即使是其中一台机器在最糟的时间崩溃了也能确保所有的 Job 得到执行。
Quartz 中集群如何工作
一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。意思是你必须对每个节点分别启动或停止。不像许多应用服务器的集群,独立的 Quartz 节点并不与另一其的节点或是管理节点通信。Quartz 应用是通过数据库表来感知到另一应用的。
图:表示了每个节点直接与数据库通信,若离开数据库将对其他节点一无所知
创建Quartz数据库表
因为Quartz 集群依赖于数据库,所以必须首先创建Quartz数据库表。Quartz 包括了所有被支持的数据库平台的 SQL 脚本。在 <quartz_home>/docs/dbTables 目录下找到那些 SQL 脚本,这里的 <quartz_home> 是解压 Quartz 分发包后的目录。
这里采用的Quartz 2.0.2版本,总共11张表,不同版本,表个数可能不同。数据库为mysql,用tables_mysql.sql创建数据库表。
介绍下主要的几张表:
表qrtz_job_details: 保存job详细信息,该表需要用户根据实际情况初始化
job_name:集群中job的名字,该名字用户自己可以随意定制,无强行要求
job_group:集群中job的所属组的名字,该名字用户自己随意定制,无强行要求
job_class_name:集群中个note job实现类的完全包名,quartz就是根据这个路径到classpath找到该job类
is_durable:是否持久化,把该属性设置为1,quartz会把job持久化到数据库中
job_data:一个blob字段,存放持久化job对象
表qrtz_triggers: 保存trigger信息
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表达式
表qrtz_cron_triggers:存储cron表达式表
trigger_name: qrtz_triggers表trigger_name的外键
trigger_group: qrtz_triggers表trigger_group的外键
cron_expression:cron表达式
表qrtz_scheduler_state:存储集群中note实例信息,quartz会定时读取该表的信息判断集群中每个实例的当前状态
instance_name:之前配置文件中org.quartz.scheduler.instanceId配置的名字,就会写入该字段,如果设置为AUTO,quartz会根据物理机名和当前时间产生一个名字
last_checkin_time:上次检查时间
checkin_interval:检查间隔时间
配置数据库连接池
1.配置jdbc.properties文件
#mysql database setting
quartz.jdbc.driver=com.mysql.jdbc.Driver
quartz.jdbc.url=jdbc:mysql://10.10.46.145:3306/test?useUnicode=true&characterEncoding=utf-8
quartz.jdbc.username=root
quartz.jdbc.password=root
2.配置applicationContext.xml文件
- <bean id="quartzDataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
- <property name="driverClass" value="${quartz.jdbc.driver}" />
- <property name="url" value="${quartz.jdbc.url}" />
- <property name="username" value="${quartz.jdbc.username}" />
- <property name="password" value="${quartz.jdbc.password}" />
- </bean>
<bean id="quartzDataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="driverClass" value="${quartz.jdbc.driver}" /> <property name="url" value="${quartz.jdbc.url}" /> <property name="username" value="${quartz.jdbc.username}" /> <property name="password" value="${quartz.jdbc.password}" /> </bean>
3.applicationContext-quartz-timer-cluster.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:util="http://www.springframework.org/schema/util"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd"
- default-lazy-init="true">
- <description>Quartz的定时集群任务配置</description>
- <!-- Quartz集群Schduler -->
- <bean id="clusterQuartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <!-- Triggers集成 -->
- <property name="triggers">
- <list>
- <ref bean="timerTrigger" />
- </list>
- </property>
- <!-- quartz配置文件路径-->
- <property name="configLocation" value="classpath:schedule/quartz-cluster.properties" />
- <!-- 启动时延期3秒开始任务 -->
- <property name="startupDelay" value="3" />
- <!-- 保存Job数据到数据库所需的数据源 -->
- <property name="dataSource" ref="quartzDataSource" />
- <!-- Job接受applicationContext的成员变量名 -->
- <property name="applicationContextSchedulerContextKey" value="applicationContext" />
- </bean>
- <!-- Timer式 Trigger定义-->
- <bean id="timerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
- <property name="jobDetail" ref="timerJobDetail" />
- <property name="repeatInterval" value="120000" />
- </bean>
- <!--
- <bean id="timerTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
- <property name="jobDetail" ref="timerJobDetail" />
- <property name="cronExpression" value="0 0/2 * * * ?" />
- </bean> -->
- <!-- Timer JobDetail, 基于JobDetailBean实例化Job Class,可持久化到数据库实现集群 -->
- <bean id="timerJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
- <property name="jobClass" value="com.test.schedule.QuartzClusterableJob" />
- </bean>
- <!-- Timer Job的可配置属性,在job中通过applicationContext动态获取 -->
- <util:map id="timerJobConfig">
- <entry key="nodeName" value="default" />
- </util:map>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd" default-lazy-init="true"> <description>Quartz的定时集群任务配置</description> <!-- Quartz集群Schduler --> <bean id="clusterQuartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!-- Triggers集成 --> <property name="triggers"> <list> <ref bean="timerTrigger" /> </list> </property> <!-- quartz配置文件路径--> <property name="configLocation" value="classpath:schedule/quartz-cluster.properties" /> <!-- 启动时延期3秒开始任务 --> <property name="startupDelay" value="3" /> <!-- 保存Job数据到数据库所需的数据源 --> <property name="dataSource" ref="quartzDataSource" /> <!-- Job接受applicationContext的成员变量名 --> <property name="applicationContextSchedulerContextKey" value="applicationContext" /> </bean> <!-- Timer式 Trigger定义--> <bean id="timerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="timerJobDetail" /> <property name="repeatInterval" value="120000" /> </bean> <!-- <bean id="timerTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="timerJobDetail" /> <property name="cronExpression" value="0 0/2 * * * ?" /> </bean> --> <!-- Timer JobDetail, 基于JobDetailBean实例化Job Class,可持久化到数据库实现集群 --> <bean id="timerJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="com.test.schedule.QuartzClusterableJob" /> </bean> <!-- Timer Job的可配置属性,在job中通过applicationContext动态获取 --> <util:map id="timerJobConfig"> <entry key="nodeName" value="default" /> </util:map> </beans>
dataSource:项目中用到的数据源,里面包含了quartz用到的11张数据库表;
applicationContextSchedulerContextKey: 是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类中把spring上下 文以key/value的方式存放在了quartz的上下文中了,可以用applicationContextSchedulerContextKey所 定义的key得到对应的spring上下文;
configLocation:用于指明quartz的配置文件的位置
4.quartz-cluster.properties
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = ClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.skipUpdateCheck = true
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 15000
org.quartz.scheduler.instanceName属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同。
org.quartz.scheduler.instanceId 属性为 AUTO即可,基于主机名和时间戳来产生实例 ID。
org.quartz.jobStore.class属性为 JobStoreTX,将任务持久化到数据中。因为集群中节点依赖于数据库来传播 Scheduler 实例的状态,你只能在使用 JDBC JobStore 时应用 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 秒)。
5.QuartzClusterableJob.java
- /**
- * 被Spring的Quartz JobDetailBean定时执行的Job类, 支持持久化到数据库实现Quartz集群.
- *
- * 因为需要被持久化,只能在每次调度时从QuartzJobBean注入的applicationContext中动态 取出.
- */
- public class QuartzClusterableJob extends QuartzJobBean {
- private ApplicationContext applicationContext;
- /**
- * 从SchedulerFactoryBean注入的applicationContext.
- */
- public void setApplicationContext(ApplicationContext applicationContext) {
- this.applicationContext = applicationContext;
- }
- @Override
- protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
- Map config = (Map) applicationContext.getBean("timerJobConfig");
- String nodeName = (String) config.get("nodeName");
- System.out.println("quartz cluster job on node "+nodeName+" .");
- }
- }
/** * 被Spring的Quartz JobDetailBean定时执行的Job类, 支持持久化到数据库实现Quartz集群. * * 因为需要被持久化,只能在每次调度时从QuartzJobBean注入的applicationContext中动态 取出. */ public class QuartzClusterableJob extends QuartzJobBean { private ApplicationContext applicationContext; /** * 从SchedulerFactoryBean注入的applicationContext. */ public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } @Override protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException { Map config = (Map) applicationContext.getBean("timerJobConfig"); String nodeName = (String) config.get("nodeName"); System.out.println("quartz cluster job on node "+nodeName+" ."); } }
Quartz 实际并不关心你是在相同的还是不同的机器上运行节点。当集群是放置在不同的机器上时,通常称之为水平集群。节点是跑在同一台机器是,称之为垂直集群。对于垂直集群,存在着单点故障的问题。这对高可用性的应用来说是个坏消息,因为一旦机器崩溃了,所有的节点也就被有效的终止了。
当你运行水平集群时,时钟应当要同步,以免出现离奇且不可预知的行为。假如时钟没能够同步,Scheduler 实例将对其他节点的状态产生混乱。有几种简单的方法来保证时钟何持同步,而且也没有理由不这么做。最简单的同步计算机时钟的方式是使用某一个 Internet 时间服务器(Internet Time Server ITS)。
没什么会阻止你在相同环境中使用集群的和非集群的 Quartz 应用。唯一要注意的是这两个环境不要混用在相同的数据库表。意思是非集群环境不要使用与集群应用相同的一套数据库表;否则将得到希奇古怪的结果,集群和非集群的 Job 都会遇到问题。
假如你让一个非集群的 Quartz 应用与集群节点并行着运行,设法使用 JobInitializationPlugin和 RAMJobStore。
注:例子中使用的是mysql数据库,还要解决水平集群时不同机器通过ip访问mysql的问题
在mysql数据库服务器中
进入:mysql -u root -p/mysql -h localhost -u root -p mysql;
授权:grant all privileges on *.* to root@"%" identified by 'root' with grant option;
flush privileges;
它的意思是给从任意ip地址连接的用户名为root,密码为root的用户赋予所有的权限。其中的"%"为任意的ip地址,如果想设为特定的值也可以设定为特定的值。
相关推荐
在"spring3.1+hibernate4.1+struts2整合jar包"中,包含了这三个框架的最新稳定版本,确保了良好的兼容性和性能。Spring 3.1引入了更多改进,如支持JSR-330标准的依赖注入,增强了对Groovy的支持,以及对AOP的进一步...
Spring 3.1 和 XFire 1.26 是两个在Java开发中广泛使用的开源框架,主要用于构建服务导向架构(Service-Oriented Architecture, SOA)的应用程序。Spring 是一个全面的后端开发框架,提供了依赖注入、面向切面编程、...
"struct2.3+spring3.1+mybits3.1 核心Jar包和配置文件"的组合正是这样一个经典的应用架构,它将Struts2、Spring3.1和MyBatis3.1这三个流行框架整合在一起,为开发者提供了强大的MVC(Model-View-Controller)架构...
mybatis分页spring3.1+struts2 测试代码。自己写的。仅供参考。 文章地址 http://blog.csdn.net/fairyhawk/article/details/7787939
5. **整合Spring与Struts2**:将Spring的IoC容器注入到Struts2的Action类中,通常通过Spring的Struts2插件来实现。 6. **测试与优化**:完成基本配置后,进行单元测试和集成测试,确保各组件协同工作。根据需求优化...
本文将详细解析"spring3.1+hibernate4+Jpa Dao"集成的相关知识点,帮助你理解和掌握这一体系结构。 **Spring 3.1** Spring 是一个开源的应用框架,它提供了全面的编程和配置模型,用于简化Java企业级应用的开发。...
基于struts2.2+spring3.1+Mybatis3.1(SSI框架)框架开发下的JAR包整合!
在本项目中,"Spring3.1+Hibernate4.0+Struts2.3.1 零配置功能已实现"表示的是一个基于三大主流Java Web框架——Spring、Hibernate和Struts2的集成应用,且重点在于使用了注解(Annotation)进行零配置设置。...
这是一个基于Java技术栈的Web开发项目实例,使用了Spring 3.1、Hibernate 4和Struts2这三个核心框架,并且采用了注解方式进行配置。这个项目例子旨在帮助开发者理解如何在实际开发中整合这三个框架,实现MVC模式的...
在压缩包"**S2.3+S3.1+h3.6包**"中,包含了一系列的jar文件,这些文件包括了Struts2、Spring和Hibernate框架的核心库,以及可能需要的其他依赖,如数据库驱动、log4j日志库等。开发者在导入这些jar包后,需要按照...
主要使用myeclipse 2015 spring3.1+struts+hibernate3.x 实现数据库添加删除查找更新,你只要新建web project ,把代码导入进行就可以运行,create database student, create table user( `id` int(10) unsigned NOT ...
2. **配置Spring**:在Spring配置文件中,定义bean,包括数据源、SqlSessionFactory、MapperScannerConfigurer(扫描Mapper接口)以及Service和DAO层的bean。 3. **配置iBatis**:创建`mybatis-config.xml`,配置...
2、报错:org.hibernate.HibernateException: No Session found for current thread 意思是必须在transcation.isActive()条件下才能执行, 可以解决办法是:当方法不需要事务支持的时候,使用 Session ...
Struts1.2+Struts2.1.6+spring 2.0+hibernate3.1+Ibatis2.3 SSH
标题中的"spring3.1+struts2.3+hibernate4.1小例子"指的是一款基于Java的Web应用程序开发示例,它整合了三个流行的技术框架:Spring 3.1、Struts 2.3和Hibernate 4.1。这个小例子可能是一个学习资源或模板,用于教授...
Struts2、Spring和Hibernate是Java Web开发中的三大框架,它们的整合是企业级应用开发中的常见实践。这个"struts2.2.3+spring3.1+hibernate3.67整合"项目旨在将这三个框架集成在一起,以实现更高效、更灵活的后端...
SSH 为 struts2.4+spring3.1+hibernate4.1的一个集成框架,是目前较流行的一种Web应用程序开源框架。 集成SSH框架的系统从职责上分为四层:表示层、业务逻辑层、数据持久层和域模块层,以帮助开发人员在短期内搭建...
Spring 3.1 和 Hibernate 是两个非常重要的Java企业级开发框架,它们在现代Web应用程序的构建中扮演着关键角色。Spring 提供了一个全面的应用程序框架,涵盖了依赖注入、AOP(面向切面编程)、数据访问、Web应用以及...
"Structs2.1+Spring3.1+Hibernate4.1"的源码组合为学习和研究SSH框架提供了一个基础平台。通过深入研究这个项目,开发者不仅可以掌握SSH的基本用法,还能了解到如何在实际项目中应用这些技术,从而提升自己的专业...
公司项目需要,搭建了SSM框架,当初想更好的熟悉SSM框架的架构及其原理,所以未使用maven,资源中包括所有的jar包,能直接运行在tomcat服务器,框架中使用了Spring的自动扫描,注解注入,AOP异常日志记录,AOP事务,...