美文网首页
SpringBoot + MySql + Quartz 集群模式

SpringBoot + MySql + Quartz 集群模式

作者: 不智鱼 | 来源:发表于2018-08-02 20:21 被阅读323次

    背景

    quartz 可用于管理调度定时任务,有集群模式和单机模式,quartz 的单机模式部署,所有任务执行信息都在内存中保存,存在单点故障,quartz 的集群模式具备高可用,自动负载均衡等特点,可保障定时任务的执行。

    1 SpringBoot + Mysql + Quartz 集群模式搭建

    注: 集群模式依赖实例所在机器之间的时间同步,请自行部署 ntp 服务进行时间同步。

    1.1 Quartz 相关表建立

    • 去官网下载 quartz, [下载地址]
    • 解压后,执行 docs/dbTables/tables_mysql_innodb.sql 脚本建表
    • 检查 db 中是否存在以下 11 个表
    +--------------------------+
    | QRTZ_BLOB_TRIGGERS       |
    | QRTZ_CALENDARS           |
    | QRTZ_CRON_TRIGGERS       |
    | QRTZ_FIRED_TRIGGERS      |
    | QRTZ_JOB_DETAILS         |
    | QRTZ_LOCKS               |
    | QRTZ_PAUSED_TRIGGER_GRPS |
    | QRTZ_SCHEDULER_STATE     |
    | QRTZ_SIMPLE_TRIGGERS     |
    | QRTZ_SIMPROP_TRIGGERS    |
    | QRTZ_TRIGGERS            |
    +--------------------------+
    

    1.2 maven 中引入 Quartz 相关包

            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz</artifactId>
                <version>2.2.1</version>
            </dependency>
            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz-jobs</artifactId>
                <version>2.2.1</version>
            </dependency>
    

    1.3 创建quartz配置文件

    org.quartz.jobStore.useProperties = false
    org.quartz.jobStore.tablePrefix = QRTZ_
    # 开启集群模式
    org.quartz.jobStore.isClustered = true
    # 集群实例检测时间间隔 ms
    org.quartz.jobStore.clusterCheckinInterval = 5000
    # misfire 任务的超时阈值 ms
    org.quartz.jobStore.misfireThreshold = 60000
    org.quartz.jobStore.txIsolationLevelReadCommitted = true
    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    
    org.quartz.scheduler.instanceId= AUTO
    org.quartz.scheduler.rmi.export = false
    org.quartz.scheduler.rmi.proxy = false
    org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
    
    # 工作线程的线程池设置
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    org.quartz.threadPool.threadCount = 5
    org.quartz.threadPool.threadPriority = 5
    org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
    

    特别解释一下这个参数 org.quartz.jobStore.misfireThreshold = 60000, misfire 任务为错过调度触发时间的任务,而 misfireThreshold 为判定触发任务为 misfire 的判定条件,比如规定 11:30 要执行一次 Job, 如果因为实例挂掉或者线程池忙导致 11:33 才触发调度,超时了 3 分钟,超时时间 > 60000ms, 因此判定为 misfire。

    判定为 misfire 的处理规则在后面的原理介绍相关文章会提及。

    1.4 生成 ScheduleFactory Bean

    @Configuration
    public class SchedulerConfig {
        @Autowired
        private DataSource dataSource;
    
        @Bean
        public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
            SchedulerFactoryBean factory = new SchedulerFactoryBean();
            factory.setSchedulerName("Cluster_Scheduler");
            factory.setDataSource(dataSource);
            factory.setApplicationContextSchedulerContextKey("applicationContext");
            factory.setQuartzProperties(quartzProperties());
            return factory;
        }
    
        @Bean
        public Properties quartzProperties() throws IOException {
            PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
            propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
    
            propertiesFactoryBean.afterPropertiesSet();
            return propertiesFactoryBean.getObject();
        }
    }
    

    1.5 定义并添加 Job

    @PersistJobDataAfterExecution
    @DisallowConcurrentExecution
    public class QuartzJob extends QuartzJobBean {
        private static final Logger logger = LoggerFactory.getLogger(QuartzJob.class);
    
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            String taskName = context.getJobDetail().getJobDataMap().getString("name");
    
            logger.info("---> Quartz job {}, {} <----", new Date(), taskName);
        }
    }
    
    private void addJob(String id, String jobName) throws SchedulerException {
        Scheduler scheduler = gSchedulerFactory.getScheduler();
    
        JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class)
                .withIdentity(id, JOB_GROUP_NAME)
                .usingJobData("name", jobName).build();
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(String.valueOf(id), TRIGGER_GROUP_NAME)
                .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")).build();
    
        scheduler.scheduleJob(jobDetail, trigger);
    }
    

    1.6 启动 Scheduler

    public void start() throws SchedulerException {
        gSchedulerFactory.getScheduler().start();
    }
    

    1.7 启动程序

    quartz 集群和其他分布式集群不一样,集群实例之间不需要互相通信,只需要和DB 交互,通过 DB 感知其他势力,实现 Job 调度。因此只需要按照普通 java 程序启动即可,扩容也只需要新启动实例,不需要做额外配置。

    下一篇会介绍 quartz 集群模式的原理。

    相关文章

      网友评论

          本文标题:SpringBoot + MySql + Quartz 集群模式

          本文链接:https://www.haomeiwen.com/subject/wxnsvftx.html