转载自 http://www./topic/486055 和 http://julylin./blog/849100
概述 虽然单个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文件 Xml代码
3.applicationContext-quartz-timer-cluster.xml Xml代码
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 Java代码
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地址,如果想设为特定的值也可以设定为特定的值。 |
|