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
相关推荐
7. **监控与日志**:为了保证集群的稳定运行,需要实时监控各个节点的状态,以及日志记录,以便于排查问题。 提供的"quartz_Cluster" Demo可能包含了一个简单的集群配置示例,通过运行和分析这个示例,你可以更深入...
计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,学习参考资料 计算机技术、IT咨询、人工智能AI理论介绍,...
Quartz 是一个开源的作业调度框架,...总结,解决 "quartz 调用两次任务" 的问题需要对 Quartz 的工作原理有深入理解,并对代码、数据库、服务器配置进行细致的排查。通过上述步骤,通常能够找到问题所在并进行修复。
- **监控与日志**:可以集成监控工具,如Quartz Admin,以便实时查看任务状态,同时确保有良好的日志记录系统,便于问题排查。 在"quartz-mybatis"压缩包中,应包含QUARTZ的配置文件、Mybatis的Mapper接口和XML...
同时,Quartz内置了日志框架,方便记录任务执行的日志,便于调试和问题排查。 总的来说,Quartz是一个功能强大的作业调度框架,它的灵活性和可扩展性使其成为企业级应用定时任务的首选。通过合理的配置和设计,我们...
- `log4j-1.2.16.jar` 是Log4j的版本1.2.16,这是一个经典的Java日志框架,用于记录应用程序运行过程中的事件,便于调试和问题排查。Quartz在运行过程中会产生许多日志信息,通过Log4j可以方便地管理和控制这些信息...
这对于定制化需求、性能优化或者排查问题都极其有价值。例如,了解 `org.quartz.simpl.SimpleThreadPool` 如何管理线程池,或者 `org.quartz.jdbcjobstore.TablePrefixAware` 如何处理多租户环境下的数据隔离,都能...
"quartz source包" 提供了 Quartz 框架的源代码,这对于理解其内部工作机制、进行定制开发或排查问题非常有帮助。 Quartz 主要包含以下几个核心概念: 1. **Job**:Job 是 Quartz 的基础,代表一个需要执行的任务...
- log4j-1.2.14.jar:这是一个经典且广泛使用的日志记录框架,提供多种级别的日志输出,如DEBUG、INFO、WARN、ERROR等,便于调试和问题排查。 - slf4j-api-1.5.10.jar 和 slf4j-log4j12-1.5.10.jar:Simple ...
同时,确保日志配置合理,便于排查问题。 - **容错与恢复**:了解Terracotta的故障转移机制,确保在节点故障时,任务能被其他节点接管。 - **性能优化**:根据系统负载调整Terracotta和Quartz的配置,例如调整线程池...
- 在分布式环境下,Quartz.NET支持多节点集群,当一个节点出现问题时,任务可以被其他节点接管。 - 调度器的集群同步策略保证了任务的一致性和可靠性。 7. **自定义扩展**: - 用户可以根据需求实现自己的插件,...
7. **异常处理与日志记录**: 为了确保任务的稳定运行,应处理可能出现的异常,并使用EF记录日志信息,以便于排查问题。 8. **部署为Windows服务**: 最后,将应用打包成Windows服务,以便在后台持续运行,不受用户...
7. **故障排查与优化** - 监控 Scheduler 状态,确保任务按预期执行。 - 调整并发执行策略,避免资源竞争。 - 使用 Job Store,如 JDBCJobStore,保证高可用性。 8. **扩展性** - Quartz 支持集群部署,允许多...
同时,Scheduler还支持集群环境,可以在多台服务器上实现任务的高可用性和负载均衡。 4. **配置与使用**: 配置Quartz通常涉及定义Job和Trigger的XML文件,以及初始化Scheduler的代码。XML文件中会声明JobDetail...
6. **配置日志**:在应用中集成log4j,通过配置文件控制日志输出,以便于调试和问题排查。 在实际项目中,可能还需要考虑任务的并发控制、异常处理、任务暂停与恢复、任务删除等操作。同时,由于log4j-1.2.14版本较...
2. **Spring与Quartz的整合**:讲解如何利用Spring的依赖注入(DI)和面向切面编程(AOP)特性,简化Quartz的配置和作业管理。通过Spring的XML配置或Java配置,可以方便地将作业和触发器绑定,实现灵活的作业调度...
3. **监控和日志**:设置监控机制,记录Job执行情况,便于问题排查。 综上所述,Spring+Quartz的组合为开发者提供了强大的定时任务调度能力,通过灵活的配置和API,可以应对各种复杂的定时任务需求。配合提供的文档...
6. **故障排查**:常见问题和解决方案,帮助用户在遇到问题时快速定位和解决。 7. **持久化机制**:Quartz如何使用数据库或其他持久化机制来存储和恢复Job和Trigger的状态。 8. **集群配置**:如果Quartz在集群...