1、问题
客户对分布式任务进行压力测试,发现分配任务时会有重复分派的情况。
2、分析
1、客户应用基于我们的框架开发,分布式任务采用框架集成的Quartz进行任务调度,客户应用测试环境采用多台服务器集群部署,因此要求Quartz按照集群方式部署,否则多个服务器下的Quartz Job会有抢单的问题发生,所以,首先要验证Quartz集群配置是否正确有效;
2、检查Job任务,看Job内部是否有抢单的情况,经分析发现AbstractQuartzService当前实现的Job接口,这就存在一个潜在的风险,当本次被调度的Job没有执行完,下次又启动了该Job时,会有任务竞争的情况;
3、客户应用基于我们的开发框架,分布式任务的启动是通过quartz插件启动的,测试时需要模拟生产环境的启动过程进行测试。
3、验证Quartz集群过程
3.1、Quartz配置
3.1.1 quartz_client.properties
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = LmsScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
# org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = SYS_TA_
org.quartz.jobStore.isClustered = true
#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@localhost:1521:orcl
org.quartz.dataSource.myDS.user = test
org.quartz.dataSource.myDS.password = test
org.quartz.dataSource.myDS.maxConnections = 5
#============================================================================
# Configure Plugins
#============================================================================
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.fileNames = conf/schedule/quartz_jobs.xml
org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
org.quartz.plugin.jobInitializer.scanInterval = 0
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
说明:
1、注意标红的内容;
2、quartz集群配置,要求集群的配置放在共享的数据库中,示例是采用oracle,quartz对应的数据库配置表需要提前创建好;
3、由于框架集成的quartz-1.6.4版本,下面的配置没有对应实现类,测试时升级为quartz-1.7.1版本
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
3.1.2 quartz_jobs
<?xml version='1.0' encoding='utf-8'?>
<quartz xmlns="http://www.opensymphony.com/quartz/JobSchedulingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opensymphony.com/quartz/JobSchedulingData
http://www.opensymphony.com/quartz/xml/job_scheduling_data_1_5.xsd"
version="1.5">
<job>
<job-detail>
<name>simpleJob</name>
<group>simpleJob</group>
<description>test_dispatcher</description>
<job-class>com.itown.dtask.service.SimpleQuartJob</job-class>
<volatility>false</volatility>
<durability>false</durability>
<recover>false</recover>
</job-detail>
<trigger>
<simple>
<name>simpleJob</name>
<group>simpleJob</group>
<job-name>simpleJob</job-name>
<job-group>simpleJob</job-group>
<repeat-count>-1</repeat-count>
<repeat-interval>10000</repeat-interval>
</simple>
</trigger>
</job>
</quartz>
3.2、编写测试类
3.2.1 Job实现类
public class SimpleQuartJob implements StatefulJob{
public void execute(JobExecutionContext jec) throws JobExecutionException {
System.out.println("SimpleQuartJob is running when " + new Date());
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
System.out.println(ex.getMessage());
}
}
}
说明:该类实现了 StatefulJob接口。
3.2.2 QuartzPluginStarter
public class QuartzPluginStarter {
private static Scheduler scheduler = null;
private static final Logger logger = Logger.getLogger(QuartzPlugin.class.getName());
public static void main(String[] args){
try {
// 从配置文件的路径中读取
String fileName = "quartz_client.properties";
File file = new File(RunModeManager.getInstance().getWorkPath(), "conf" + File.separator + "schedule" + File.separator + fileName);
logger.info("加载配置文件, file=" + file.toString());
if (!file.exists()) {
logger.warning(String.format("调度程序配置文件[%s]不存在。", file));
return;
}
SchedulerFactory sf = new StdSchedulerFactory(file.getAbsolutePath());
scheduler = sf.getScheduler();
scheduler.start();
logger.info("SchedulerFactory started");
} catch (SchedulerException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
说明:该类模拟了QuartzPlugin的实现,与生产环境启动quartz的机制相同。
3.3、集群测试
1、启动一个QuartzPluginStarter(A),观察Job的执行,正常时每次执行打印一条记录;
2、再启动一个QuartzPluginStarter(B),模拟集群环境下启动多个Quartz,同时观察A、B两个程序的执行情况,集群配置正确后,正常的结果是A或者B只有一个在执行;
3、如果是B执行,A等待,此时停掉B,观察A是否开始执行,如果开始执行就验证了Quartz集群的高可用特性。
测试结论:验证结果符合预期,Quartz集群环境下,只有一个节点下的Quartz生效,当启用的Quartz出问题时,Quartz集群会启动其他的Quartz节点,实现高可用。
4、后续工作
1、检查并确认客户应用Quartz配置是否正确;
2、修改AbstractQuartzService实现的接口,由原来实现Job改为实现StatefulJob接口。
5、参考
http://www.quartz-scheduler.org/
http://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/index.html
相关推荐
quartz集群调度机制调研及源码分析,基于quartz 1.7版本
一个基于springboot的quartz集群dome。 向http://localhost:9090/job/addjob注入3个参数 类名:(及时定时任务的类如:com.ybjdw.site.job.NewJob) 组名:随意 定时启动方法:如“0/3 * * * * ?”(每3秒启动一次...
本文章是关于springboot集成quartz集群的步骤,LZ亲测。
SSH框架,主要实现了OA中的RABC权限管理,整合了Quartz,并支持Quartz集群
quartz集群Sql大放送,包含几十种数据库的初始sql,赶紧送上分来吧,记得评价返分
springboot 集成 quartz 集群 加 sql 等 文章介绍 单机加集群都有 https://blog.csdn.net/weixin_42749765/article/details/88532413
java + quartz实现定时任务,实现集群配置,在集群环境下多节点运行定时Quartz定任务,就会存在重复处理任务的现象,为解决这一问题,下面我将介绍使用 Quartz 的 TASK ( 12 张表)实例化到数据库,基于数据库自动...
NULL 博文链接:https://lostangel0214.iteye.com/blog/1163503
NULL 博文链接:https://daoshud1.iteye.com/blog/1955099
自己弄了将近一天的成果。主要是修改MethodInvokingJobDetailFactoryBean这个类。
quartz集群时需要在数据库中创建的表结构(oracle,mysql,sqlserver,h2sql等22种数据库)
quartz在集群环境下的最终解决方案quartz在集群环境下的最终解决方案
quartz集群各种数据库建表脚本,基于quartz2.2.1版本。
NULL 博文链接:https://vista-move.iteye.com/blog/2274246
NULL 博文链接:https://kissroom112.iteye.com/blog/2224442
spring4.0.6+quartz 2.2.3 集群示例
最近公司项目上线,需要把app部署在多台服务器上,但只能让其中一台服务器的job执行,一台服务器挂了,另一台还能继续执行job,通过网上查找资料,都是java工程的方式,不好部署并测试,经过二天辛苦整合,终于整理成...
NULL 博文链接:https://soulshard.iteye.com/blog/337886
spring 集成 quartz ,支持集群,job支持spring@Autowired注入及@Resource注入