




已阅读5页,还剩14页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Quartz集群配置1 Quartz集群原理概述1.1 实现集群的基本原理公众企业应用几乎都会碰到任务调度的需求,就拿论坛来说:每隔半个小时生成精华文章的RSS文件,每天凌晨统计论坛用户的积分排名,每隔30分钟执行锁定用户解锁任务。任务调度本身涉及到多线程并发、运行时间规则制定和解析、场景保持与恢复、线程池维护等诸多方面的工作。如果直接使用自定义线程这种刀耕火种的原始办法,开发任务调度程序是一项颇具挑战性的工作。Java开源的好处就是:领域问题都能找到现成的解决方案。OpenSymphony所提供的Quartz自2001年发布版本以来已经被众多项目作为任务调度的解决方案,Quartz在提供巨大灵活性的同时并未牺牲其简单性,它所提供的强大功能使你可以应付绝大多数的调度需求。Quartz 在开源任务调度框架中的翘首,它提供了强大任务调度机制,难能可贵的是它同时保持了使用的简单性。Quartz 允许开发人员灵活地定义触发器的调度时间表,并可以对触发器和任务进行关联映射。此外,Quartz提供了调度运行环境的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。此外,Quartz还提供了组件式的侦听器、各种插件、线程池等功能。Quartz最新版本是2.1.3,Quartz是通过借助关系数据库和JDBC作业存储来实现集群管理的,集群通过故障切换和负载平衡的功能,能给调度器带来高可用性和伸缩性。目前Quartz集群只能工作在JDBC-Jobstore (JobStoreTX 或者JobStoreCMT)方式下,从本质上来说,是使集群上的每一个节点通过共享同一个数据库来工作的(Quartz通过启动两个维护线程来维护数据库状态实现集群管理,一个是检测节点状态线程,一个是恢复任务线程)。负载平衡是自动完成的,集群的每个节点会尽快触发任务。当一个触发器的触发时间到达时,第一个节点将会获得任务(通过锁定),成为执行任务的节点。故障切换的发生是在当一个节点正在执行一个或者多个任务失败的时候。当一个节点失败了,其他的节点会检测到并且标识在失败节点上正在进行的数据库中的任务。任何被标记为可恢复(任务详细信息的requests recovery属性)的任务都会被其他的节点重新执行;没有标记可恢复的任务只会被释放出来,将会在下次相关触发器触发时执行。集群通过故障切换和负载平衡的功能,能给调度器带来高可用性和伸缩性。目前集群只能工作在JDBC- Jobstore (JobStoreTX或者JobStoreCMT)方式下,从本质上来说,是使集群上的每一个节点通过共享同一个数据库来工作的(Quartz通过启动两个维护线程来维护数据库状态实现集群管理,一个是检测节点状态线程,一个是恢复任务线程)。负载平衡是自动完成的,集群的每个节点会尽快触发任务。当一个触发器的触发时间到达时,第一个节点将会获得任务(通过锁定),成为执行任务的节点。故障切换的发生是在当一个节点正在执行一个或者多个任务失败的时候。当一个节点失败了,其他的节点会检测到并且标识在失败节点上正在进行的数据库中的任务。任何被标记为可恢复(任务详细信息的requests recovery属性)的任务都会被其他的节点重新执行。没有标记可恢复的任务只会被释放出来,将会在下次相关触发器触发时执行。1.2 Quartz体系结构Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器、任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述:Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。通过该类的构造函数可以更具体地了解它的功用:JobDetail(java.lang.String name, java.lang.String group, java.lang.Class jobClass),该构造函数要求指定Job的实现类,以及任务在Scheduler中的组名和Job名称。Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等。Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。针对不同时间段类型,Quartz在org.quartz.impl.calendar包下提供了若干个Calendar的实现类,如AnnualCalendar、MonthlyCalendar、WeeklyCalendar分别针对每年、每月和每周进行定义。Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例。ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。1.3 Quartz数据库表我们使用quartz-2.1.3.zip,因为Quartz集群依赖于数据库,所以必须首先创建Quartz数据库表,Quartz包括了所有被支持的数据库平台的SQL脚本。在 /docs/dbTables 目录下找到那些SQL脚本(这里的 是解压Quartz分发包后的目录),这里采用的Quartz 2.1.3版本,总共11张表,不同版本,表个数可能不同。数据库为oracle,用tables_oracle.sql创建数据库表。全部表如下所示。1.3.1 Quartz用到的表表名描述QRTZ_BLOG_TRIGGERSTrigger作为Blob类型存储(用于Quartz用户用JDBC创建他们自己定制的Trigger类型,JobStore 并不知道如何存储实例的时候)QRTZ_CALENDARS以Blob类型存储Quartz的Calendar信息QRTZ_CRON_TRIGGERS存储Cron Trigger,包括Cron表达式和时区信息QRTZ_FIRED_TRIGGERS存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息QRTZ_JOB_DETAILS存储每一个已配置的Job的详细信息QRTZ_LOCKS存储程序的非观锁的信息(假如使用了悲观锁)QRTZ_PAUSED_TRIGGER_GRPS存储已暂停的Trigger组的信息QRTZ_SCHEDULER_STATE存储少量的有关 Scheduler的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)QRTZ_JOB_LISTENERS存储有关已配置的 JobListener的信息QRTZ_SIMPLE_TRIGGERS存储简单的 Trigger,包括重复次数,间隔,以及已触的次数QRTZ_SIMPROP_TRIGGERSQRTZ_TRIGGERS存储已配置的 Trigger的信息1.3.2 Quartz权限信息表(qrtz_locks)说明:tables_oracle.sql里有相应的dml初始化1.3.3 任务详细信息表(qrtz_job_details)说明:保存job详细信息,该表需要用户根据实际情况初始化job_name: 集群中job的名字,该名字用户自己可以随意定制,无强行要求。job_group: 集群中job的所属组的名字,该名字用户自己随意定制,无强行要求。job_class_name:集群中job实现类的完全包名,quartz就是根据这个路径到classpath找到该job类的。is_durable:是否持久化,把该属性设置为1,quartz会把job持久化到数据库中job_data:一个blob字段,存放持久化job对象。1.3.4 触发器与任务关联表(qrtz_fired_triggers)存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息。1.3.5 调度器状态表(qrtz_scheduler_state)说明:集群中note实例信息,quartz定时读取该表的信息判断集群中每个实例的当前状态。 instance_name: 配置文件中org.quartz.scheduler.instanceId配置的名字,就会写 入该字段,如果设置为AUTO,quartz会根据物理机名和当前时间产生一个名字。 last_checkin_time: 上次检查时间 checkin_interval: 检查间隔时间1.3.6 trigger信息表(qrtz_triggers) 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表达式1.3.7 cron表达式表(qrtz_cron_triggers)trigger_name: qrtz_triggers表trigger_name的外键 trigger_group: qrtz_triggers表trigger_group的外键 cron_expression:cron表达式1.4 Quartz配置文件说明默认文件名称perties,通过设置org.quartz.jobStore.isClustered属性为true来激活集群特性。在集群中的每一个实例都必须有一个唯一的instance id (org.quartz.scheduler.instanceId 属性), 但是应该有相同的scheduler instance name (org.quartz.scheduler.instanceName),也就是说集群中的每一个实例都必须使用相同的perties 配置文件。除了以下几种例外,配置文件的内容其他都必须相同:a.不同的线程池大小。b.不同的org.quartz.scheduler.instanceId属性值(这个可以很容易做到,设定为AUTO即可)。注意:1、永远不要在不同的机器上运行集群,除非他们的时钟是使用某种形式的同步服务(守护)非常有规律的运行(时钟必须在一分一秒内)来达到同步。2、永远不要触发一个非集群的实例,如果其他的实例正在同一个数据库表上运行。你将使你的数据严重腐蚀,出现非预期行为。2 JAVASE环境中Quartz集群配置实现一个jobpackage quartz.test;import java.util.Date;import mons.logging.Log;import mons.logging.LogFactory;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;/如果有想反复执行的动作,作业,任务就把相关的代码写在execute这个方法里,前提:实现Job这个接口/至于SimpleJob这个类什么时候实例化,execute这个方法何时被调用,我们不用关注,交给Quartzpublic class SimpleJob implements Job private static Log _log = LogFactory.getLog(SimpleJob.class); public SimpleJob() public void execute(JobExecutionContext context) throws JobExecutionException /这个作业只是简单的打印出作业名字和此作业运行的时间 String jobName = context.getJobDetail().getFullName(); _(SimpleJob says: + jobName + executing at + new Date(); System.out.println(-Calling the job -shang- + new Date(); 定义调度器对上面的job进行调度package quartz.test;import java.util.Date;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.quartz.SchedulerFactory;import org.quartz.SchedulerMetaData;import org.quartz.SimpleTrigger;import org.quartz.TriggerUtils;import org.quartz.impl.StdSchedulerFactory;import mons.logging.LogFactory;import mons.logging.Log;/* 这个例子展示Quartz的 简单触发器 所具备的基本调度能力*/public class SimpleTriggerExample public void run() throws Exception Log log = LogFactory.getLog(SimpleTriggerExample.class); (- 初始化 -); / 首先我们得获得一个调度器 SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); (- 初始化结束 -); (- 调度一个作业,简单的说就是给一个任务定一个时间启动 -); / 所有的作业都可以在sched.start()被调用前调度 / 获取下个15秒的开始,如当前是10秒,则在15秒执行,如实16秒,则在30秒执行 / 如果不喜欢这个方法,自己定义一个Date也可以 long ts = TriggerUtils.getNextGivenSecondDate(null, 15).getTime(); / job1将在ts这个时间触发执行,我们的作业叫job1,属于group1组 JobDetail job = new JobDetail(job1, group1, SimpleJob.class); SimpleTrigger trigger = new SimpleTrigger(trigger1, group1, new Date(ts);/此处ts可以自己设置一个Date trigger.setRepeatCount(100); trigger.setRepeatInterval(5*1000L); / 将作业加入调度队列,返回作业执行时间 Date ft = sched.scheduleJob(job, trigger); sched.start();/调度器启动作业,相当于神舟7号点火了,具体什么时候飞天,还得看火着的速度 (job.getFullName() + 将在: + ft + 执行 并且重复执行: + trigger.getRepeatCount() + 次, 每次执行间隔 + trigger.getRepeatInterval() / 1000 + 秒); (- 等待1分钟. -); try / wait five minutes to show jobs Thread.sleep(1000*60); / executing. catch (Exception e) (- 关闭调度器 -); sched.shutdown(true); (- 关闭结束-); public static void main(String args) throws Exception SimpleTriggerExample example = new SimpleTriggerExample(); example.run(); 配置文件最好自己指定一个,否则会使用quartz.jar包里面的默认perties文件#=# Configure Main Scheduler Properties 主要属性配置#=org.quartz.scheduler.instanceName = Schedulerorg.quartz.scheduler.instanceId = AUTOorg.quartz.scheduler.rmi.export = xy = false#=# Configure ThreadPool 线程池配置#=org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPoolorg.quartz.threadPool.threadCount = 3org.quartz.threadPool.threadPriority = 5#=# jobStore 任务存储配置#=#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore #org.quartz.jobStore.misfireThreshold = MISFIRE_THRESHOLD #ororg.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegateorg.quartz.jobStore.useProperties = falseorg.quartz.jobStore.dataSource = myDSorg.quartz.jobStore.tablePrefix = qrtz_org.quartz.jobStore.isClustered = false#=# Date Source 数据源的配置#=org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver org.quartz.dataSource.myDS.URL = jdbc:mysql:/localhost:3306/quartz_tables?useUnicode=true&characterEncoding=utf8 org.quartz.dataSource.myDS.user = rootorg.quartz.dataSource.myDS.password = 123456org.quartz.dataSource.myDS.maxConnections = 52.1 配置Quartz使用集群2.1.1 集群配置为Quartz配置集群环境的步骤比设置类似的JAVAEE集群环境容易的多:1. 配置每个节点的perties文件。2. 配置JDBCJobStore。3. 使用Scheduler信息(Job和Trigger) 装载数据库。4. 启动每个Quartz节点。5. 通过设置org.quartz.jobStore.isClustered属性为true来激活集群特性。在集群中的每一个实例都必须有一个唯一的instance id (org.quartz.scheduler.instanceId 属性), 但是应该有相同的scheduler instance name (org.quartz.scheduler. instanceName),也就是说集群中的每一个实例都必须使用相同的 perties配置文件。除了以下几种例外,配置文件的内容其他都必须相同:不同的线程池大小,不同的org.quartz.scheduler.instanceId属性值(这个可以很容易做到,设定为AUTO即可)。注意: 永远不要在不同的机器上运行集群,除非他们的时钟是使用某种形式的同步服务(守护)非常有规律的运行(时钟必须在一分一秒内)来达到同步。还有: 永远不要触发一个非集群的实例,如果其他的实例正在同一个数据库表上运行。你将使你的数据严重腐蚀,出现非预期行为。2.1.2 配置实例环境:Windows xp 主机:Vmware 7虚拟的两台RHEL5:Server A:30Server B:31(防火墙已关闭)Mysql数据库 安装在windows 主机上Server A:perties文件配置信息如下:#=# Configure Main Scheduler Properties #=org.quartz.scheduler.instanceName = mySchedulerorg.quartz.scheduler.instanceId = AUTO#=# Configure ThreadPool #=org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPoolorg.quartz.threadPool.threadCount = 3org.quartz.threadPool.threadPriority = 5#=# Configure jobStore#=org.quartz.jobStore.misfireThreshold = 60000org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegateorg.quartz.jobStore.dataSource = myDSorg.quartz.jobStore.tablePrefix = qrtz_#是否集群org.quartz.jobStore.isClustered = trueorg.quartz.jobStore.clusterCheckinInterval = 200#=# Non-Managed Configure Date Source#=org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driverorg.quartz.dataSource.myDS.URL = jdbc:mysql:/3:3306/quartz_cluster?useUnicode=true&characterEncoding=utf8org.quartz.dataSource.myDS.user = rootorg.quartz.dataSource.myDS.password = 123456org.quartz.dataSource.myDS.maxConnections = 5Java代码:A: package cluster;package cluster;import java.util.Date;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;public class SimpleJob implements Job public SimpleJob() public void execute(JobExecutionContext context) throws JobExecutionException /String jobName = context.getJobDetail().getFullName(); System.out.println(A Calling the job -shang- + new Date(); B: package clusterpackage cluster;import java.util.Date;import mons.logging.Log;import mons.logging.LogFactory;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.quartz.SchedulerFactory;import org.quartz.SimpleTrigger;import org.quartz.TriggerUtils;import org.quartz.impl.StdSchedulerFactory;public class SimpleTriggerExample public void run() throws Exception Log log = LogFactory.getLog(SimpleTriggerExample.class); (- initial-); SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); (- initial end-); (- scheduler a job-); long ts = TriggerUtils.getNextGivenSecondDate(null, 15).getTime(); JobDetail job = new JobDetail(job1, group1, SimpleJob.class); SimpleTrigger trigger = new SimpleTrigger(trigger1, group1, new Date(ts); trigger.setRepeatCount(100); trigger.setRepeatInterval(5*1000L); Date ft = sched.scheduleJob(job, trigger); /sched.start(); (job.getFullName() + time: + ft + repeatcount: + trigger.getRepeatCount() + repeatInterval + trigger.getRepeatInterval() / 1000 + s); (- wait 1 minite-); try / wait five minutes to show jobs Thread.sleep(1000*60); / executing. catch (Exception e) (- close scheduler-); sched.shutdown(true); (- end-); public static void main(String args) throws Exception SimpleTriggerExample example = new SimpleTriggerExample(); example.run(); C: package clusterpackage cluster;import org.quartz.*;import org.quartz.impl.StdSchedulerFactory;public class JobreScheduler public static void main(String args)trySchedulerFactory sf = new StdSchedulerFactory();Scheduler sche = sf.getScheduler();sche.start();System.out.println(C scheduler start);catch (Exception e)e.printStackTrace();Server B:perties文件配置信息如下:#=# Configure Main Scheduler Properties #=org.quartz.scheduler.instanceName = mySchedulerorg.quartz.scheduler.instanceId = AUTO#=# Configure ThreadPool#=org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPoolorg.quartz.threadPool.threadCount = 3org.quartz.threadPool.threadPriority = 5#=# Configure jobStore#=org.quartz.jobStore.misfireThreshold = 60000org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegateorg.quartz.jobStore.dataSource = myDSorg.quartz.jobStore.tablePrefix = qrtz_#是否集群org.quartz.jobStore.isClustered = trueorg.quartz.jobStore.clusterCheckinInterval = 200#=# Non-Managed Configure Date Source #=org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver org.quartz.dataSource.myDS.URL = jdbc:mysql:/3:3306/quartz_cluster?useUnicode=true&characterEncoding=utf8 org.quartz.dataSource.myDS.user = rootorg.quartz.dataSource.myDS.password =
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年崇左市凭祥市国防动员办公室招聘考试笔试试题(含答案)
- 图书测试实验室企业制定与实施新质生产力项目商业计划书
- 传动带智能调度系统创新创业项目商业计划书
- 【联考】江苏省南京市、盐城市两地联考2025届高三上学期期末调研考试数学试题含答案
- 二胡演出AI应用行业跨境出海项目商业计划书
- 节日庆典茶馆行业跨境出海项目商业计划书
- 《采购管理》第十讲教案(3课时)
- 2025届高考数学二轮复习查漏补缺课时练习十第10讲函数的图像文
- 2022年全国职业院校技能大赛:网络系统管理项目-模块B-样题1
- DB1310T 267-2022 维勃稠度仪校准规范
- SA8000-2014社会责任绩效委员会SPT组织架构、职责和定期检讨及评审会议记录
- 搅拌釜式反应器搅拌釜式反应器课件
- 湖北省实验动物从业人员培训考试题库及答案(供参考)
- 回顾性中医医术实践资料(医案)表
- 英语四级考试试题与答案
- 天津市宝坻区2022-2023学年数学五年级第二学期期末考试试题含解析
- 医德医风教育培训内容【5篇】
- 2023-2024学年湖北省恩施市小学语文六年级期末评估测试题附参考答案和详细解析
- 住院患者突发呼吸困难应急预案与处理流程
- 2021局限期小细胞肺癌放疗原则、规范与进展
- 土木工程施工组织课程设计
评论
0/150
提交评论