虽然单个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.2.1版本,总共11张表,不同版本,表个数可能不同。数据库为mysql,用tables_mysql_innodb.sql创建数据库表。
配置数据库连接池
1.配置jdbc.properties文件
- jdbc.driverClassName=com.mysql.jdbc.Driver
- jdbcjdbc.url=jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
- jdbc.username=root
- jdbc.password=kfs
2.配置applicationContext.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:jdbc="http://www.springframework.org/schema/jdbc"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
- ">
- <context:component-scan base-package="com.sundoctor" />
- <!-- 属性文件读入 -->
- <bean id="propertyConfigurer"
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>classpath:jdbc.properties</value>
- </list>
- </property>
- </bean>
- <!-- 数据源定义,使用c3p0 连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
- destroy-method="close">
- <property name="driverClass" value="${jdbc.driverClassName}" />
- <property name="jdbcUrl" value="${jdbc.url}" />
- <property name="user" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- <property name="initialPoolSize" value="${cpool.minPoolSize}" />
- <property name="minPoolSize" value="${cpool.minPoolSize}" />
- <property name="maxPoolSize" value="${cpool.maxPoolSize}" />
- <property name="acquireIncrement" value="${cpool.acquireIncrement}" />
- <property name="maxIdleTime" value="${cpool.maxIdleTime}" />
- </bean>
- </beans>
创建Job测试服务类
- package com.sundoctor.quartz.cluster.example;
- import java.io.Serializable;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.stereotype.Service;
- @Service("simpleService")
- public class SimpleService {
- private static final long serialVersionUID = 122323233244334343L;
- private static final Logger logger = LoggerFactory.getLogger(SimpleService.class);
- public void testMethod1(){
- //这里执行定时调度业务
- logger.info("testMethod1.......1");
- }
- public void testMethod2(){
- logger.info("testMethod2.......2");
- }
- }
创建两个Job类MyQuartzJobBean1、MyQuartzJobBean2
- package com.sundoctor.quartz.cluster.example;
- import org.quartz.DisallowConcurrentExecution;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- import org.quartz.PersistJobDataAfterExecution;
- import org.quartz.SchedulerException;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.context.ApplicationContext;
- import org.springframework.scheduling.quartz.QuartzJobBean;
- @PersistJobDataAfterExecution
- @DisallowConcurrentExecution// 不允许并发执行
- public class MyQuartzJobBean1 extends QuartzJobBean {
- private static final Logger logger = LoggerFactory.getLogger(MyQuartzJobBean1.class);
- @Override
- protected void executeInternal(JobExecutionContext jobexecutioncontext) throws JobExecutionException {
- SimpleService simpleService = getApplicationContext(jobexecutioncontext).getBean("simpleService",
- SimpleService.class);
- simpleService.testMethod1();
- }
- private ApplicationContext getApplicationContext(final JobExecutionContext jobexecutioncontext) {
- try {
- return (ApplicationContext) jobexecutioncontext.getScheduler().getContext().get("applicationContextKey");
- } catch (SchedulerException e) {
- logger.error("jobexecutioncontext.getScheduler().getContext() error!", e);
- throw new RuntimeException(e);
- }
- }
- }
配置 Quartz 使用集群
1.配置节点的 quartz.properties 文件
org.quartz.scheduler.instanceName = TestScheduler1
org.quartz.scheduler.instanceId = AUTO
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
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 秒)。
2.配置applicationContext-quartz.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"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- <bean name="quartzScheduler"
- class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <property name="dataSource">
- <ref bean="dataSource" />
- </property>
- <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
- <property name="configLocation" value="classpath:quartz.properties" />
- <property name="triggers">
- <list>
- <ref bean="trigger1" />
- <ref bean="trigger2" />
- </list>
- </property>
- </bean>
- <bean id="jobDetail1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
- <property name="jobClass">
- <value>com.sundoctor.quartz.cluster.example.MyQuartzJobBean1</value>
- </property>
- <property name="durability" value="true" />
- <property name="requestsRecovery" value="true" />
- </bean>
- <bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
- <property name="jobDetail" ref="jobDetail1" />
- <property name="cronExpression" value="0/30 * * ? * * *" />
- </bean>
- <bean id="jobDetail2" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
- <property name="jobClass">
- <value>com.sundoctor.quartz.cluster.example.MyQuartzJobBean2</value>
- </property>
- <property name="durability" value="true" />
- <property name="requestsRecovery" value="true" />
- </bean>
- <bean id="trigger2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
- <property name="jobDetail" ref="jobDetail2" />
- <property name="cronExpression" value="0/10 * * ? * * *" />
- </bean>
- </beans>
dataSource:项目中用到的数据源,里面包含了quartz用到的11张数据库表;
applicationContextSchedulerContextKey: 是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类中把spring上下 文以key/value的方式存放在了SchedulerContext中了,可以用applicationContextSchedulerContextKey所 定义的key得到对应spring 的ApplicationContext;
configLocation:用于指明quartz的配置文件的位置
requestsRecovery
requestsRecovery属性必须设置为 true,当Quartz服务被中止后,再次启动或集群中其他机器接手任务时会尝试恢复执行之前未完成的所有任务。
运行Quartz集群
在相同或不同的机器上运行com.sundoctor.quartz.cluster.example.test.MainTest进行测试,在本例中只是简单打印一下日志。
- package com.sundoctor.quartz.cluster.example.test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class MainTest {
- /**
- * @param args
- */
- public static void main(String[] args) {
- ApplicationContext springContext = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext.xml","classpath:applicationContext-quartz.xml"});
- }
- }
Quartz 实际并不关心你是在相同的还是不同的机器上运行节点。当集群是放置在不同的机器上时,通常称之为水平集群。节点是跑在同一台机器是,称之为垂直集群。对于垂直集群,存在着单点故障的问题。这对高可用性的应用来说是个坏消息,因为一旦机器崩溃了,所有的节点也就被有效的终止了。
当你运行水平集群时,时钟应当要同步,以免出现离奇且不可预知的行为。假如时钟没能够同步,Scheduler 实例将对其他节点的状态产生混乱。有几种简单的方法来保证时钟何持同步,而且也没有理由不这么做。最简单的同步计算机时钟的方式是使用某一个 Internet 时间服务器(Internet Time Server ITS)。
没什么会阻止你在相同环境中使用集群的和非集群的 Quartz 应用。唯一要注意的是这两个环境不要混用在相同的数据库表。意思是非集群环境不要使用与集群应用相同的一套数据库表;否则将得到希奇古怪的结果,集群和非集群的 Job 都会遇到问题。
假如你让一个非集群的 Quartz 应用与集群节点并行着运行,设法使用 JobInitializationPlugin和 RAMJobStore
相关推荐
本项目"动态定时任务 SpringBoot quartz集群分布式。动态指定任意-demo-quartz-dynamic.zip"正是这样一个示例,它展示了如何在SpringBoot应用中实现动态管理和调度Quartz定时任务,并且支持在分布式环境下运行。 ...
在分布式环境中,Quartz集群能够实现任务的高可用性和负载均衡。Spring Quartz则是将Quartz与Spring框架整合,使得任务调度变得更加方便。 一、Quartz集群原理 Quartz集群的基本思想是多个Quartz Scheduler实例...
基于JDBC-Jobstore的方式实现集群(有数据库JobStoreTX或JobStoreCMT) 二.TerracottaJobStore的配置(无数据库的集群) 本文介绍的是JDBC-Jobstore基于数据库的集群: 1.目前,群集仅适用于JDBC-Jobstore...
3. **监控和管理**: 实现对Quartz集群的监控,如任务状态、运行时性能等,以便及时发现和解决问题。 总结,Quartz+Spring的分布式集群调度方案能够帮助开发者构建稳定且可扩展的定时任务系统。通过合理配置和实践,...
而Quartz则是一款功能强大的作业调度库,它允许开发者定义、调度和执行任务。本篇文章将详细探讨如何在Spring Boot项目中整合Quartz实现任务定时调度。 首先,我们需要理解Spring Boot与Quartz的整合基础。Spring ...
- 考虑使用监控工具(如Prometheus+Grafana)监控Quartz集群的运行状态,以便及时发现和解决问题。 通过以上知识点的学习和实践,开发者可以熟练掌握在Spring环境中使用Quartz实现分布式集群的作业调度,提升系统...
【标题】:基于Spring Boot和Quartz的分布式任务调度系统 在现代企业级应用中,任务调度是一项重要的功能,用于按预定的时间间隔执行特定的任务,例如数据同步、报表生成、清理过期数据等。本项目名为“schedule-...
Quartz集群需要将所有调度信息(如Job、Trigger)存储在一个共享的持久化存储中,以便所有集群节点都能访问。这通常通过实现`ISchedulerFactory`接口的`StdSchedulerFactory`类和数据库连接来完成。数据库可以选择...
在Quartz集群中,多个Quartz服务器共享同一个“作业存储”(Job Store),这个存储可以是关系数据库或者分布式的存储系统。当一个服务器触发一个作业时,其他服务器会看到这个作业已经被触发,因此不会重复执行。这...
通过这种方式,Quartz集群可以实现任务的分布式执行和高可用性。 在实际应用中,你可能还会遇到如负载均衡、任务同步、节点间的通信等问题,需要对Quartz的API和原理有深入理解才能更好地应对。通过阅读官方文档、...
在分布式环境中,Quartz可以通过Cluster模式实现任务的高可用性和负载均衡,使得在一个集群中的任何节点都可以处理作业,确保任务的稳定执行。 在动态管理定时任务方面,Spring Boot结合Quartz可以实现对定时任务的...
SpringBoot整合Quartz实现定时任务调度是企业级应用中常见的需求,主要用于自动化执行某些周期性的...在集群环境中,通过配置和Quartz的内置机制,我们可以实现任务的分布式执行和故障恢复,提高系统的稳定性和可靠性。
此外,还需要配置集群策略,如`org.quartz.impl.jdbcjobstore.ClusterManager`,确保任务不被多个节点重复执行。 8. **监控与管理**: 可以使用Quartz提供的Web管理界面(如`AdminUI`)或API来查看和管理任务。...
在实际应用中,可能会使用如ZooKeeper这样的分布式协调服务来帮助Quartz集群管理状态。 在压缩包文件"oa_ssh"中,可能包含了项目的所有源代码、配置文件、数据库脚本等资源,开发者可以通过这些文件了解和学习SSH...
Quartz集群通过共享内存中的状态来实现任务的分配和执行,当一个节点失败时,其他节点能够接管未完成的任务。实现Quartz集群,需要配置多个Quartz服务器共享同一份数据库存储,用于保存Job、Trigger以及运行状态等...
集群分布式系统设计及注意事项 分布式计算模式已经成为现代IT架构的核心部分,它通过将计算任务分布在多个网络连接的计算节点上,以提高系统的可扩展性、可靠性和计算效率。集群分布式系统设计往往涉及到服务器的...
本文介绍了如何基于Crawler4j和Quartz框架构建一个分布式爬虫系统。分布式爬虫系统是为了解决大规模数据采集的效率和稳定性问题。在大数据时代,网络爬虫技术是数据分析的重要基础,通过自动化方式抓取网络数据,...
在IT行业中,Spring框架是Java应用开发中的基石,而Quartz则是广泛...通过上述步骤,你已经掌握了Spring集成Quartz集群配置的基本概念。在实践中,根据具体需求调整配置,可以实现高效、稳定且可扩展的任务调度系统。
在构建Quartz集群时,为了实现高可用性和任务的分布式处理,需要在多个节点之间共享状态信息,这就涉及到数据库的支持。数据库在这里起到了存储作业和触发器信息的作用,确保在集群中的各个节点间能够正确协调和执行...