搭建高可用Quartz集群

首页 > 科技

搭建高可用Quartz集群

来源:迷途的羔羊 发布时间:2023-07-05 12:11

本章节,我们先从原理上来熟悉Quartz集群,然后基于springboot,带着大家搭建高可用的quartz集群。

Quartz集群原理

如上图所示,我们用3台服务器和一个共享的数据库组成了集群,该集群不同于我们常见的主从集群或含有观察者的分布式集群,每一台服务器都是独立运行的,服务器之间也不存在心跳等状态检测机制,而是通过数据库来获取状态信息,这种做法在集群方式中并不多见。

Quartz 如何感知故障

在集群环境的quartz中有org.quartz.jobStore.clusterCheckinInterval这样一个参数据,其表示多久进行一次状态检查,quartz服务器每隔参数设定的时间会向数据库发起一次状态登记,该行为称为CHECKIN。

那么如何判断判断节点是否为故障节点呢?就是根据上一次CHECKIN的时间与检查时间之间是否明显(加上了一定的冗余时间窗口)超出了一个状态登记的时间周期,假如超过了,则以为其处于故障状态。

Quartz集群如何分派任务

在通常情况下,我们都是但愿任务仅在集群中某一台机器中执行,而非并发执行带来难以预期的后果,这种情况下,就存在着如何分派任务的问题。

Quartz中存在两种行锁STATE_ACCESS和TRIGGER_ACCESS,分别代表着状态访问锁和触发器访问锁。

我们需要明确的一点是,集群中的Quartz都是同构的。在这个条件下,任务会在各个集群服务器统一时刻被唤起(当然,需要保证服务器之间的时间同步),抢占共享数据库中触发器访问锁,抢到锁的服务器拥有本次任务的执行权限,为获取到锁的服务器退出本次任务的执行。

Quartz集群的搭建

我们以springboot集成quartz搭建集群环境为例,关注的重点在于配置文件的部门说明。

1、进入官网下载软件。

2、在下载包中docs/dbTables找到对应数据库类型的建表语句(若在某些目标版本中未找到该文件,也可以到开源社区或其它相近版本中查找)并执行。

3、创建springboot项目

1)Quartz枢纽引包

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

2)在resource下创建quartz.properites核心配置

#quartz集群配置 #调度标识名 集群中每一个实例都必需使用相同的名称 org.quartz.scheduler.instanceName=DefaultQuartzScheduler#ID设置为自动获取 每一个必需不同 org.quartz.scheduler.instanceId=AUTOorg.quartz.scheduler.makeSchedulerThreadDaemon=false#线程池的实现类(一般使用SimpleThreadPool即可满意需求) org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool#指定在线程池里面创建的线程是否是守护线程org.quartz.threadPool.makeThreadsDaemons=false#指定线程数,1-100org.quartz.threadPool.threadCount:10#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5) org.quartz.threadPool.threadPriority:5#数据留存方式为数据库持久化 org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX#数据库署理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满意大部分数据库 org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate#表的前缀,默认QRTZ_ org.quartz.jobStore.tablePrefix=QRTZ_#是否加入集群org.quartz.jobStore.isClustered=true# 信息留存时间 默认值60秒 org.quartz.jobStore.misfireThreshold=25000

3) 创建一个配置类引入quartz.properites相关值

@Configurationpublic class QuartzConfigure {// 配置文件路径 private static final String QUARTZ_CONFIG = "/quartz.properties"; @Autowired @Qualifier(value = "dataSource") private DataSource dataSource; @Value("${quartz.cronExpression}") private String cronExpression;/** * 从quartz.properties文件中读取Quartz配置属性 * @return * @throws IOException */ @Bean public Properties quartzProperties() throws IOException { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_CONFIG)); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } /** * JobFactory与schedulerFactoryBean中的JobFactory相互依赖,留意bean的名称 * 在这里为JobFactory注入了Spring上下文 * * @param applicationContext * @return */ @Bean public JobFactory buttonJobFactory(ApplicationContext applicationContext) { AutoWiredSpringBeanToJobFactory jobFactory = new AutoWiredSpringBeanToJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } /** * * @param buttonJobFactory 为SchedulerFactory配置JobFactory * @param cronJobTrigger * @return * @throws IOException */ @Bean public SchedulerFactoryBean schedulerFactoryBean(JobFactory buttonJobFactory, Trigger... cronJobTrigger) throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setJobFactory(buttonJobFactory); factory.setOverwriteExistingJobs(true); factory.setAutoStartup(true); // 设置自行启动 factory.setQuartzProperties(quartzProperties()); factory.setTriggers(cronJobTrigger); factory.setDataSource(dataSource);// 使用应用的dataSource替代quartz的dataSource return factory; } /** * 配置JobDetailFactory * JobDetailFactoryBean与CronTriggerFactoryBean相互依赖,留意bean的名称 * * @return */ @Bean public JobDetailFactoryBean buttonobDetail() { //集群模式下必需使用JobDetailFactoryBean,MethodInvokingJobDetailFactoryBean 类中的 methodInvoking 方法,是不支持序列化的 JobDetailFactoryBean jobDetail = new JobDetailFactoryBean(); jobDetail.setDurability(true); jobDetail.setRequestsRecovery(true); jobDetail.setJobClass(ButtonTimerJob.class); return jobDetail; } /** * 配置详细执行规则 * @param buttonobDetail * @return */ @Bean public CronTriggerFactoryBean cronJobTrigger(JobDetail buttonobDetail) { CronTriggerFactoryBean tigger = new CronTriggerFactoryBean(); tigger.setJobDetail(buttonobDetail); tigger.setStartDelay(2000); //延迟启动 tigger.setCronExpression(cronExpression); //从application.yml文件读取 return tigger; }}

4)编写JobFactory类并将其注入到Spring容器中

public class AutoWiredSpringBeanToJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext(final ApplicationContext context) { beanFactory = context.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job);return job; }}

5)创建执行的Job

@DisallowConcurrentExecutionpublic class ButtonTimerJob implements Job{ private static final Logger logger = LoggerFactory.getLogger(ButtonTimerJob.class);/** * 核心方法,Quartz Job真正的执行逻辑. * @param JobExecutionContext中封装有Quartz运行所需要的所有信息 * @throws JobExecutionException execute()方法只答应抛出JobExecutionException异常 */ @Override public void execute(JobExecutionContext context) throws JobExecutionException { logger.info("--------------定时任务执行逻辑---------------------"); }}

6)创建application.yml文件

server: port: 8080logging: file: logback.xmlspring: dataSource: url: jdbc:mysql://***********:3306/button-pro?characterEncoding=utf-8&autoReconnect=true&allowMultiQueries=true&useSSL=true&zeroDateTimeBehavior=convertToNull username: root password: ****** driver-class-name: com.mysql.jdbc.Drivertype: com.zaxxer.hikari.HikariDataSource hikari: minimum-idle: 5 maximum-pool-size: 15 idle-timeout: 30000 pool-name: DatebookHikariCP max-lifetime: 1800000 connection-timeout: 30000 connection-test-query: "SELECT 1"quartz: cronExpression: 0/5 * 8-20 * * ?

7)创建springboot启动类以及日志配置,与此主题关联度较低,不进行详细描述。

本章节,我们先从原理上来熟悉Quartz集群,然后基于springboot,带着大家搭建高可用的quartz集群。

Quartz集群原理

如上图所示,我们用3台服务器和一个共享的数据库组成了集群,该集群不同于我们常见的主从集群或含有观察者的分布式集群,每一台服务器都是独立运行的,服务器之间也不存在心跳等状态检测机制,而是通过数据库来获取状态信息,这种做法在集群方式中并不多见。

Quartz 如何感知故障

在集群环境的quartz中有org.quartz.jobStore.clusterCheckinInterval这样一个参数据,其表示多久进行一次状态检查,quartz服务器每隔参数设定的时间会向数据库发起一次状态登记,该行为称为CHECKIN。

那么如何判断判断节点是否为故障节点呢?就是根据上一次CHECKIN的时间与检查时间之间是否明显(加上了一定的冗余时间窗口)超出了一个状态登记的时间周期,假如超过了,则以为其处于故障状态。

Quartz集群如何分派任务

在通常情况下,我们都是但愿任务仅在集群中某一台机器中执行,而非并发执行带来难以预期的后果,这种情况下,就存在着如何分派任务的问题。

Quartz中存在两种行锁STATE_ACCESS和TRIGGER_ACCESS,分别代表着状态访问锁和触发器访问锁。

我们需要明确的一点是,集群中的Quartz都是同构的。在这个条件下,任务会在各个集群服务器统一时刻被唤起(当然,需要保证服务器之间的时间同步),抢占共享数据库中触发器访问锁,抢到锁的服务器拥有本次任务的执行权限,为获取到锁的服务器退出本次任务的执行。

Quartz集群的搭建

我们以springboot集成quartz搭建集群环境为例,关注的重点在于配置文件的部门说明。

1、进入官网下载软件。

本章节,我们先从原理上来熟悉Quartz集群,然后基于springboot,带着大家搭建高可用的quartz集群。

Quartz集群原理

如上图所示,我们用3台服务器和一个共享的数据库组成了集群,该集群不同于我们常见的主从集群或含有观察者的分布式集群,每一台服务器都是独立运行的,服务器之间也不存在心跳等状态检测机制,而是通过数据库来获取状态信息,这种做法在集群方式中并不多见。

Quartz 如何感知故障

在集群环境的quartz中有org.quartz.jobStore.clusterCheckinInterval这样一个参数据,其表示多久进行一次状态检查,quartz服务器每隔参数设定的时间会向数据库发起一次状态登记,该行为称为CHECKIN。

那么如何判断判断节点是否为故障节点呢?就是根据上一次CHECKIN的时间与检查时间之间是否明显(加上了一定的冗余时间窗口)超出了一个状态登记的时间周期,假如超过了,则以为其处于故障状态。

Quartz集群如何分派任务

在通常情况下,我们都是但愿任务仅在集群中某一台机器中执行,而非并发执行带来难以预期的后果,这种情况下,就存在着如何分派任务的问题。

Quartz中存在两种行锁STATE_ACCESS和TRIGGER_ACCESS,分别代表着状态访问锁和触发器访问锁。

我们需要明确的一点是,集群中的Quartz都是同构的。在这个条件下,任务会在各个集群服务器统一时刻被唤起(当然,需要保证服务器之间的时间同步),抢占共享数据库中触发器访问锁,抢到锁的服务器拥有本次任务的执行权限,为获取到锁的服务器退出本次任务的执行。

Quartz集群的搭建

我们以springboot集成quartz搭建集群环境为例,关注的重点在于配置文件的部门说明。

1、进入官网下载软件。

上一篇:微信支付上架... 下一篇:起底美国年收...
猜你喜欢
热门阅读
同类推荐