搭建高可用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、進入官網下載軟體。

上一篇:微信支付上架... 下一篇:起底美國年收...
猜你喜歡
熱門閱讀
同類推薦