`

Quartz集群问题分析与排查

阅读更多

1、问题

         客户对分布式任务进行压力测试,发现分配任务时会有重复分派的情况。

2、分析

         1、客户应用基于我们的框架开发,分布式任务采用框架集成的Quartz进行任务调度,客户应用测试环境采用多台服务器集群部署,因此要求Quartz按照集群方式部署,否则多个服务器下的Quartz Job会有抢单的问题发生,所以,首先要验证Quartz集群配置是否正确有效;

         2、检查Job任务,看Job内部是否有抢单的情况,经分析发现AbstractQuartzService当前实现的Job接口,这就存在一个潜在的风险,当本次被调度的Job没有执行完,下次又启动了该Job时,会有任务竞争的情况;

         3、客户应用基于我们的开发框架,分布式任务的启动是通过quartz插件启动的,测试时需要模拟生产环境的启动过程进行测试。

3、验证Quartz集群过程

     3.1Quartz配置

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、注意标红的内容;

2quartz集群配置,要求集群的配置放在共享的数据库中,示例是采用oraclequartz对应的数据库配置表需要提前创建好;

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、启动一个QuartzPluginStarterA),观察Job的执行,正常时每次执行打印一条记录;

2、再启动一个QuartzPluginStarterB),模拟集群环境下启动多个Quartz,同时观察AB两个程序的执行情况,集群配置正确后,正常的结果是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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics