quartz集群部署方式解决方案

简介: quartz集群部署方式解决方案

需求


最近有一个项目需要从原来的单机部署修改为 集群方式部署,因为银行要求所有的的服务不能有单点的情况,所以我们需要 对该项目就行改造,别的需求改造还是比较容易的,但是项目中采用了quartz执行定时任务,所以我们需要改造这个地方,在本文中采用quartz自身支持的基于DB的集群部署方案。


版本


2.2.3


创建DB


sql文件地址:https://download.csdn.net/download/u013045437/15534461

数据字段说明:https://blog.csdn.net/hao134838/article/details/114291197


pom文件引入包

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

定时任务xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <!-- 调度器lazy-init='false'那么容器启动就会执行调度程序 -->
    <bean id="myJobFactory" class="com.jack.platformweb.task.service.MyJobFactory"></bean>
    <bean id="startQuertz " lazy-init="false" autowire="no"
          class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobFactory" ref="myJobFactory"/>
        <property name="dataSource" ref="urgeRobotDataSource"/>
        <property name="configLocation" value="classpath:properties/quartz.properties"/>
        <!--这个是必须的,QuartzScheduler延时启动,应用启动完后 QuartzScheduler再启动-->
        <property name="startupDelay" value="30"/>
        <!--这个是可选,QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了-->
        <property name="overwriteExistingJobs" value="true"/>
        <!-- 允许在Quartz上下文中使用Spring实例工厂 -->
        <property name="applicationContextSchedulerContextKey" value="applicationContext"/>
        <property name="triggers">
            <list>
                <ref bean="sendCaseTrigger"/>
            </list>
        </property>
    </bean>
    <!-- 推送任务 -->
    <bean id="sendCaseTaskClass" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass">
            <value>com.jack.platformweb.quartz.service.SendCaseTaskService</value>
        </property>
        <property name="durability" value="true"/>
        <property name="requestsRecovery" value="true"/>
    </bean>
    <bean id="sendCaseTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="sendCaseTaskClass"/>
        <property name="cronExpression" value="0/20 * * * * ?"/> <!-- //每5分钟执行一次 -->
    </bean>
</beans>

上面配置文件有几个点需要说明一下:


1、<bean id="myJobFactory" class="com.jack.platformweb.task.service.MyJobFactory"></bean>

这是我们自己定义的一个Factory,主要是解决我们在定时任务中可以自动注入我们的业务service

package com.jack.platformweb.task.service;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
public class MyJobFactory extends AdaptableJobFactory {
    //这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        //进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}


2、<property name="dataSource" ref="urgeRobotDataSource"/>  urgeRobotDataSource 就是我们自己项目中配置的数据源,可以与mybatis使用一个


其余的一些配置就和我们xml配置quartz 的方式差不多了,只是这种 部署方式控制粒度到类上,目前还没有找到控制到方法上的解决方案。


属性配置

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = Mscheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.jobStore.clusterCheckinInterval=20000
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3
org.quartz.threadPool.threadPriority = 5
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = true
org.quartz.jobStore.dataSource = myDS
#数据库表开头表示
org.quartz.jobStore.tablePrefix = qrtz_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.maxMisfiresToHandleAtATime=1

任务类代码

package com.jack.platformweb.quartz.service;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
 * @author zhenghao
 * @description: 推送案件任务
 * @date 2020/3/2011:10
 */
@Service
@Transactional
@PersistJobDataAfterExecution
@DisallowConcurrentExecution// 不允许并发执行
public class SendCaseTaskService extends QuartzJobBean {
    private static Logger log = LoggerFactory.getLogger(SendCaseTaskService.class);
//    @Autowired
//    private FsCallBaseService fsCallBaseService;
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) {
        //业务逻辑
//        fsCallBaseService.sendCaseAll();
        log.info("task_task_tak");
    }
}


总结


通过上面的方式我们就完成了基于DB的quartz的集群部署方式,关于这种方案的的原理网上有很多的文章就行介绍,其实非常的简单,就是讲执行任务写到数据库中,多个部署节点都基于同一个DB就行并发控制。


这种解决方案有几个弊端:


1、每一个定时任务的方法都需要一个类,这里需要改的工作量比较大,暂时还没有找到基于注解的,粒度到方法上的集群部署方式。


2、多个部署节点的集机器需要进行时间同步。


这里主要是考虑到改造工作量大,并且xml配置方式复杂,所以这几天也在考虑其他的方案,基于现有的部署要求,可以使用AOP+分布式锁(基于rediss)来实现,在一篇博客中分享这种解决方案。

目录
相关文章
|
存储 负载均衡 监控
分布式定时任务,你了解多少?基于Quartz实现分布式定时任务解决方案!
定时任务系统在应用平台中的重要性不言而喻,特别是互联网电商、金融等行业更是离不开定时任务。在任务数量不多、执行频率不高时,单台服务器完全能够满足。但是随着业务逐渐增加,定时任务系统必须具备高可用和水平扩展的能力,单台服务器已经不能满足需求。因此需要把定时任务系统部署到集群中,实现分布式定时任务系统集群。
4734 1
分布式定时任务,你了解多少?基于Quartz实现分布式定时任务解决方案!
|
5月前
|
监控 Dubbo 应用服务中间件
通用快照方案问题之Sentinel与SpringCloud和Dubbo的整合如何解决
通用快照方案问题之Sentinel与SpringCloud和Dubbo的整合如何解决
50 0
|
7月前
|
消息中间件 人工智能 Java
Spring Boot+RocketMQ 实现多实例分布式环境下的事件驱动
Spring Boot+RocketMQ 实现多实例分布式环境下的事件驱动
178 1
|
前端开发 Java 调度
SpringCloud微服务实战——搭建企业级开发框架(四十二):集成分布式任务调度平台XXL-JOB,实现定时任务功能
定时任务几乎是每个业务系统必不可少的功能,计算到期时间、过期时间等,定时触发某项任务操作。在使用单体应用时,基本使用Spring提供的注解即可实现定时任务,而在使用微服务集群时,这种方式就要考虑添加分布式锁来防止多个微服务同时运行定时任务而导致同一个任务重复执行。
984 55
SpringCloud微服务实战——搭建企业级开发框架(四十二):集成分布式任务调度平台XXL-JOB,实现定时任务功能
|
7月前
|
Java 应用服务中间件 调度
xxl-job任务调度2.0.2升级到2.3.0版本,执行器改造过程中经验总结
xxl-job任务调度2.0.2升级到2.3.0版本,执行器改造过程中经验总结
546 0
|
存储 Java 关系型数据库
分布式定时任务框架Quartz总结和实践(2)—持久化到Mysql数据库
本文主要介绍分布式定时任务框架Quartz集成SpringBoot持久化数据到Mysql数据库的操作,上一篇文章使用Quartz创建定时任务都是保存在内存中,如果服务重启定时任务就会失效,所以Quartz官方也提供将定时任务等信息持久化到Mysql数据库的功能,本文主要实现这种Quartz的这种使用方式。
936 0
分布式定时任务框架Quartz总结和实践(2)—持久化到Mysql数据库
|
存储 SQL Java
分布式任务调度框架(一):Quartz
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,是完全由java开发的一个开源的任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。其功能类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能,作为一个优秀的开源调度框架
683 0
分布式任务调度框架(一):Quartz
|
存储 开发框架 Java
分布式定时任务框架Quartz总结和实践(1)
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。
197 0
|
NoSQL Java 数据处理
【Spring专题】「开发指南」手把手教你将@Schedule任务调度升级为分布式调度@DistributeSchedule
【Spring专题】「开发指南」手把手教你将@Schedule任务调度升级为分布式调度@DistributeSchedule
467 0
【Spring专题】「开发指南」手把手教你将@Schedule任务调度升级为分布式调度@DistributeSchedule
|
存储 Java 数据库连接
分布式任务调度框架ApiBoot Quartz内的两种任务存储方式
`Quartz`是一款比较优秀的分布式任务调度框架,`ApiBoot`对其封装之前就有两种任务存储方式,分别是:`memory`(内存方式)、`jdbc`(数据库方式),不过我们需要编写一些繁琐的代码配置,`ApiBoot`实现了集成后,可快速应用到项目中