1. 场景介绍
好吧,笔者所做的是一个小项目,虽说项目不大,但是项目也是集群部署的,项目中任务调度采用的是quartz,jobstore存储在ram,当然这对于一些重复执行无重大影响的任务并没有什么问题,但是后台中有几个任务,例如数据统计任务,会导致quartz定时任务在多个节点重复执行,造成了资源消耗;
我们的需求: 集群任务:下发一个集群任务时,执行任务节点的重启和销毁并不会影响任务执行,假设任务在该节点执行中,该节点因异常原因被销毁,调度中心需要将该任务重新下发到正常节点中执行
非集群任务: 各个节点各自执行,不用关心其他节点执行情况
恰巧我们的项目中既有集群任务,也有非集群任务,所以在不增加系统复杂度的情况下使用quartz任务调度解决集群任务调度是首选,非集群任务调度,quartz本身也支持,不过,一些小任务,没必要使用,所以采用的是spring task作为轻型任务调度
2. 本例实现
实现手段:quartz集群任务+spring task 轻型任务调度
官网不知咋地,无法访问,所幸github地址还可用:
https://github.com/quartz-scheduler/quartz
mysql quartz 表结构创建,一共11张表
# In your Quartz properties file, you'll need to
set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
By
: Ron Cordell - roncordell
# I didn
't see this anywhere, so I thought I'
d post it here. This
is
the script
from
Quartz
to
create
the tables
in
a MySQL
database
, modified
to
use INNODB instead
of
MYISAM.
DROP
TABLE
IF
EXISTS
QRTZ_FIRED_TRIGGERS;
DROP
TABLE
IF
EXISTS
QRTZ_PAUSED_TRIGGER_GRPS;
DROP
TABLE
IF
EXISTS
QRTZ_SCHEDULER_STATE;
DROP
TABLE
IF
EXISTS
QRTZ_LOCKS;
DROP
TABLE
IF
EXISTS
QRTZ_SIMPLE_TRIGGERS;
DROP
TABLE
IF
EXISTS
QRTZ_SIMPROP_TRIGGERS;
DROP
TABLE
IF
EXISTS
QRTZ_CRON_TRIGGERS;
DROP
TABLE
IF
EXISTS
QRTZ_BLOB_TRIGGERS;
DROP
TABLE
IF
EXISTS
QRTZ_TRIGGERS;
DROP
TABLE
IF
EXISTS
QRTZ_JOB_DETAILS;
DROP
TABLE
IF
EXISTS
QRTZ_CALENDARS;
CREATE
TABLE
QRTZ_JOB_DETAILS(
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
JOB_NAME
VARCHAR
(
190
)
NOT
NULL
,
JOB_GROUP
VARCHAR
(
190
)
NOT
NULL
,
DESCRIPTION
VARCHAR
(
250
)
NULL
,
JOB_CLASS_NAME
VARCHAR
(
250
)
NOT
NULL
,
IS_DURABLE
VARCHAR
(
1
)
NOT
NULL
,
IS_NONCONCURRENT
VARCHAR
(
1
)
NOT
NULL
,
IS_UPDATE_DATA
VARCHAR
(
1
)
NOT
NULL
,
REQUESTS_RECOVERY
VARCHAR
(
1
)
NOT
NULL
,
JOB_DATA BLOB
NULL
,
PRIMARY
KEY
(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_TRIGGERS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
TRIGGER_NAME
VARCHAR
(
190
)
NOT
NULL
,
TRIGGER_GROUP
VARCHAR
(
190
)
NOT
NULL
,
JOB_NAME
VARCHAR
(
190
)
NOT
NULL
,
JOB_GROUP
VARCHAR
(
190
)
NOT
NULL
,
DESCRIPTION
VARCHAR
(
250
)
NULL
,
NEXT_FIRE_TIME BIGINT(
13
)
NULL
,
PREV_FIRE_TIME BIGINT(
13
)
NULL
,
PRIORITY
INTEGER
NULL
,
TRIGGER_STATE
VARCHAR
(
16
)
NOT
NULL
,
TRIGGER_TYPE
VARCHAR
(
8
)
NOT
NULL
,
START_TIME BIGINT(
13
)
NOT
NULL
,
END_TIME BIGINT(
13
)
NULL
,
CALENDAR_NAME
VARCHAR
(
190
)
NULL
,
MISFIRE_INSTR
SMALLINT
(
2
)
NULL
,
JOB_DATA BLOB
NULL
,
PRIMARY
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN
KEY
(SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES
QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
TRIGGER_NAME
VARCHAR
(
190
)
NOT
NULL
,
TRIGGER_GROUP
VARCHAR
(
190
)
NOT
NULL
,
REPEAT_COUNT BIGINT(
7
)
NOT
NULL
,
REPEAT_INTERVAL BIGINT(
12
)
NOT
NULL
,
TIMES_TRIGGERED BIGINT(
10
)
NOT
NULL
,
PRIMARY
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_CRON_TRIGGERS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
TRIGGER_NAME
VARCHAR
(
190
)
NOT
NULL
,
TRIGGER_GROUP
VARCHAR
(
190
)
NOT
NULL
,
CRON_EXPRESSION
VARCHAR
(
120
)
NOT
NULL
,
TIME_ZONE_ID
VARCHAR
(
80
),
PRIMARY
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_SIMPROP_TRIGGERS
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
TRIGGER_NAME
VARCHAR
(
190
)
NOT
NULL
,
TRIGGER_GROUP
VARCHAR
(
190
)
NOT
NULL
,
STR_PROP_1
VARCHAR
(
512
)
NULL
,
STR_PROP_2
VARCHAR
(
512
)
NULL
,
STR_PROP_3
VARCHAR
(
512
)
NULL
,
INT_PROP_1
INT
NULL
,
INT_PROP_2
INT
NULL
,
LONG_PROP_1 BIGINT
NULL
,
LONG_PROP_2 BIGINT
NULL
,
DEC_PROP_1
NUMERIC
(
13
,
4
)
NULL
,
DEC_PROP_2
NUMERIC
(
13
,
4
)
NULL
,
BOOL_PROP_1
VARCHAR
(
1
)
NULL
,
BOOL_PROP_2
VARCHAR
(
1
)
NULL
,
PRIMARY
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_BLOB_TRIGGERS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
TRIGGER_NAME
VARCHAR
(
190
)
NOT
NULL
,
TRIGGER_GROUP
VARCHAR
(
190
)
NOT
NULL
,
BLOB_DATA BLOB
NULL
,
PRIMARY
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN
KEY
(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_CALENDARS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
CALENDAR_NAME
VARCHAR
(
190
)
NOT
NULL
,
CALENDAR BLOB
NOT
NULL
,
PRIMARY
KEY
(SCHED_NAME,CALENDAR_NAME))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
TRIGGER_GROUP
VARCHAR
(
190
)
NOT
NULL
,
PRIMARY
KEY
(SCHED_NAME,TRIGGER_GROUP))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_FIRED_TRIGGERS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
ENTRY_ID
VARCHAR
(
95
)
NOT
NULL
,
TRIGGER_NAME
VARCHAR
(
190
)
NOT
NULL
,
TRIGGER_GROUP
VARCHAR
(
190
)
NOT
NULL
,
INSTANCE_NAME
VARCHAR
(
190
)
NOT
NULL
,
FIRED_TIME BIGINT(
13
)
NOT
NULL
,
SCHED_TIME BIGINT(
13
)
NOT
NULL
,
PRIORITY
INTEGER
NOT
NULL
,
STATE
VARCHAR
(
16
)
NOT
NULL
,
JOB_NAME
VARCHAR
(
190
)
NULL
,
JOB_GROUP
VARCHAR
(
190
)
NULL
,
IS_NONCONCURRENT
VARCHAR
(
1
)
NULL
,
REQUESTS_RECOVERY
VARCHAR
(
1
)
NULL
,
PRIMARY
KEY
(SCHED_NAME,ENTRY_ID))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_SCHEDULER_STATE (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
INSTANCE_NAME
VARCHAR
(
190
)
NOT
NULL
,
LAST_CHECKIN_TIME BIGINT(
13
)
NOT
NULL
,
CHECKIN_INTERVAL BIGINT(
13
)
NOT
NULL
,
PRIMARY
KEY
(SCHED_NAME,INSTANCE_NAME))
ENGINE=INNODB;
CREATE
TABLE
QRTZ_LOCKS (
SCHED_NAME
VARCHAR
(
120
)
NOT
NULL
,
LOCK_NAME
VARCHAR
(
40
)
NOT
NULL
,
PRIMARY
KEY
(SCHED_NAME,LOCK_NAME))
ENGINE=INNODB;
CREATE
INDEX IDX_QRTZ_J_REQ_RECOVERY
ON
QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE
INDEX IDX_QRTZ_J_GRP
ON
QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
CREATE
INDEX IDX_QRTZ_T_J
ON
QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE
INDEX IDX_QRTZ_T_JG
ON
QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE
INDEX IDX_QRTZ_T_C
ON
QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE
INDEX IDX_QRTZ_T_G
ON
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE
INDEX IDX_QRTZ_T_STATE
ON
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE
INDEX IDX_QRTZ_T_N_STATE
ON
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE
INDEX IDX_QRTZ_T_N_G_STATE
ON
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE
INDEX IDX_QRTZ_T_NEXT_FIRE_TIME
ON
QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE
INDEX IDX_QRTZ_T_NFT_ST
ON
QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE
INDEX IDX_QRTZ_T_NFT_MISFIRE
ON
QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE
INDEX IDX_QRTZ_T_NFT_ST_MISFIRE
ON
QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE
INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP
ON
QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE
INDEX IDX_QRTZ_FT_TRIG_INST_NAME
ON
QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE
INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY
ON
QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE
INDEX IDX_QRTZ_FT_J_G
ON
QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE
INDEX IDX_QRTZ_FT_JG
ON
QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE
INDEX IDX_QRTZ_FT_T_G
ON
QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE
INDEX IDX_QRTZ_FT_TG
ON
QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
COMMIT
;
quartz.properties配置
jobstore 为ram的配置
org.quartz.scheduler.instanceName = test
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.simpl.RAMJobStore
jobstore 为jdbc的配置
org.quartz.scheduler.instanceName = test
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
配置详解:https://blog.csdn.net/sanfye/article/details/49204307
示例任务编写及spring配置
非集群任务:
@Component
public class HelloJob {
public void sayHello(){
System.out.println("hello 非集群");
集群任务:
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class NewJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println("test execute now 集群:"+System.currentTimeMillis());
spring 配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
定时任务分类:
集群模式 : 所有节点,只有一个节点最终执行
非集群模式:各个节点都执行
<context:component-scan base-package="com.ncs.quartz" />
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="minPoolSize" value="${jdbc.minPoolSize}" />
<property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}" />
<property name="acquireIncrement" value="${jdbc.acquireIncrement}" />
<property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
<property name="testConnectionOnCheckin" value="false" />
<property name="testConnectionOnCheckout" value="true" />
</bean>
<bean name="quartzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="overwriteExistingJobs" value="true" />
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties" />
<property name="startupDelay" value="2" />
<property name="jobFactory" ref="autowireJobFactory" />
<property name="triggers">
<ref bean="news_trigger" />
</list>
</property>
</bean>
<bean id="news_jobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.ncs.quartz.job.NewJob" />
<property name="durability" value="true" />
<property name="requestsRecovery" value="true" />
<property name="name" value="news_jobDetail"/>
</bean>
<bean id="news_trigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="news_jobDetail" />
<property name="cronExpression" value="0/10 * * * * ?" />
<property name="timeZone" value="GMT+8:00" />
<property name="name" value="news_trigger"/>
</bean>
<task:scheduler id="springRAMScheduler" pool-size="1" />
<task:scheduled-tasks scheduler="springRAMScheduler" >
<task:scheduled ref="helloJob" method="sayHello" cron="0/1 * * * * ?" />
</task:scheduled-tasks>
</beans>
注意点:由于任务的实例化是由quartz来实现,没有注入spring容器,所以在job中依赖其他容器中bean十分不方便,所以需要实现jobfactory,把实例化的bean注入spring容器即可
bean工厂如下:
* @author 桃源
* 2018年8月29日 上午11:18:32
* userfor:将quartzjob 注入spring容器,使得jobbean可以使用 Autowire 依赖容器对象
@Component
public class AutowireJobFactory extends SpringBeanJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
从图中可以看到,hello job 是在每个节点中都执行的
test job 只在其中一个节点执行
每个节点通过db锁来抢占任务的执行权
我们关掉节点1,会发现节点2会执行集群任务,只要节点中有可运行的节点,任务最终就会执行成功
3. 扩展
本案例适合一些小项目,不增加系统复杂度,方便维护
如果系统中调度程序多,节点也多,java中开源调度任务框架也有很多
例如:
Elastic-Job:http://elasticjob.io/index_zh.html
xxl-job:https://github.com/xuxueli/xxl-job
各位可以自行了解下
1. 场景介绍好吧,笔者所做的是一个小项目,虽说项目不大,但是项目也是集群部署的,项目中任务调度采用的是quartz,jobstore存储在ram,当然这对于一些重复执行无重大影响的任务并没有什么问题,但是后台中有几个任务,例如数据统计任务,会导致quartz定时任务在多个节点重复执行,造成了资源消耗; 我们的需求: 集群任务:下发一个集群任务时,执行任务节点的重启和销毁并不会影响任务执行...
一、前言:
虽然单个Quartz实例能给予我们很好的任务job调度能力,但它不能满足典型的企业需求,如可伸缩性、高可靠性满足。假如你需要故障转移的能力并能运行日益增多的 Job,Quartz集群势必成为你应用的一部分了。使用 Quartz 的集群能力可以更好的支持你的业务需求,并且即使是其中一台机器在最糟的时间挂掉了也能确保所有的 Job 得到执行。
二、Quart
假如你让一个非集群的 Quartz 应用与集群节点并行着运行,设法使用 JobInitializationPlugin和 RAMJobStore
Quartz支持可选节点执行jobquartz集群,会自动将触发的job均衡的分发到各个节点。不过我现在有一个特殊的job,希望触发后可以在每个节点(或是指定的节点)执行。
百度、Google 了半天。。。没找到答案。
后来自己...
在每月的某一天
在一年中的某些日子
特定时间除外的时间(如商业节假日除外)not on certain days listed within a registered Calendar (such as business holidays)
重复特定次数
一、问题背景
美团CRM系统中每天有大量的后台任务需要调度执行,如构建索引、统计报表、周期同步数据等等,要求任务调度系统具备高可用性、负载均衡特性,可以管理并监控任务的执行流程,以保证任务的正确执行。
二、历史方案
美团CRM系统的任务调度模块经历了以下历史方案。
1. Crontab+SQL
每天晚上运行定时任务,通过SQL脚本+crontab方式执行,例如,
0 2 * * * /xxx/mtcrm/shell/mtcrm_daily_stat.sql //每天凌晨2:0..
有关quartz集群的配置方案,大家可以参阅博文《Spring之——quartz集群(Oracle数据源)》和《Spring之——quartz集群(MySQL数据源)》
quartz存储job方式就分三种,我们最常用的也是quartz默认的是RAMJobStore,RAMJobStore顾名思义就是把job的相关信息存储在内存里,如果用spring配置quartz的job信息的话,所有信息是
在测试时由于先测试的
集群,导致在测试
非集群工作线程调度
任务时,
集群同样会调起
任务,不断调试,查看源码,均未发现异常,最后查看文档,原来
quartz有3种JOB存储方式,
非集群存储在内存中,而
集群是持久化在了数据库中,启动服务时,首先后加载配置文件中的job信息并持久化到数据库中,由于没有清理表记录,所以
集群在启动时,虽然从配置文件中没有加载到
任务信息,但从数据库中获取到了,所以导致了这一现象。
在
集群环境下,大家会碰到一直困扰的问题,即多个 APP 下如何用
quartz 协调处理自动化 JOB 。
大家想象一下,现在有 A , B , C3 台机器同时作为
集群服务器对外统一提供 SERVICE :
A , B , C 3 台机器上各有一个
QUARTZ ,他们会按照即定的 SCHEDULE 自动执行各自的
任务。
我们先不说实现什么功能,就说这样的架构其实有点像多线程。
1、Quartz任务调度的基本实现原理
Quartz是OpenSymphony开源组织在任务调度领域的一个开源项目,完全基于Java实现。作为一个优秀的开源调度框架,Quartz具有以下特点:
(1)强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
(2)灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;
(3...