javascript
Springboot整合Quartz集群部署以及配置Druid数据源
參考鏈接:
https://blog.csdn.net/wangmx1993328/article/details/105441308
https://blog.csdn.net/qq_39669058/article/details/90411497
參數配置連接:https://github.com/wangmaoxiong/quartzjdbc/blob/master/src/main/resources/application-cluster.yml
factory.setWaitForJobsToCompleteOnShutdown(true);
確認這個配置集群需要配置嗎?
false
開源項目若依定時任務配置
package com.ruoyi.quartz.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import javax.sql.DataSource; import java.util.Properties;/*** 定時任務配置* * @author ruoyi*/ @Configuration public class ScheduleConfig {@Beanpublic SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource){SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setDataSource(dataSource);// quartz參數Properties prop = new Properties();//實例名稱可以自定義prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");prop.put("org.quartz.scheduler.instanceId", "AUTO");// 線程池配置prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");prop.put("org.quartz.threadPool.threadCount", "20");prop.put("org.quartz.threadPool.threadPriority", "5");// JobStore配置prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");// 集群配置prop.put("org.quartz.jobStore.isClustered", "true");prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "false");// sqlserver 啟用prop.put("org.quartz.jobStore.misfireThreshold", "12000");prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");factory.setQuartzProperties(prop);//實例名稱可以自定義factory.setSchedulerName("RuoyiScheduler");// 延時啟動factory.setStartupDelay(1);factory.setApplicationContextSchedulerContextKey("applicationContextKey");// 可選,QuartzScheduler// 啟動時更新己存在的Job,這樣就不用每次修改targetObject后刪除qrtz_job_details表對應記錄了factory.setOverwriteExistingJobs(true);factory.setWaitForJobsToCompleteOnShutdown(true);// 設置自動啟動,默認為truefactory.setAutoStartup(true);return factory;} }一句話概括Quartz:
Quart分布式調度任務是通過數據庫實現的,搶占式調度,一個任務只能在一個節點上執行,他的集群也僅僅是解決了單點故障(任務級別),實現了高可用,多個任務在集群中負載均衡調度,并沒有解決任務分片的問題,不能實現水平擴展,如果執行大量的短任務,各個節點頻繁的競爭數據庫鎖,節點越多這種情況越嚴重,性能會很低下。
版本為:SpringBoot 2.x,Quartz 2.3.0,Durid 1.1.9
這里不再使用c3p0數據源,在boot2.x中spring-boot-starter-quartz依賴默認是不依賴c3p0數據源的,如果要使用需要自己單獨引用c3p0數據源,在quartz.properties配置下就可以了,這里使用的Druid數據源。
首先引入依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.43</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.9</version></dependency>Druid-spring-boot-starter:
https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
application.yml文件配置,這里面配置的Druid數據源相關的,沒有配置其他的,很單純的
server:port: 8080 spring:application:name: quartzdatasource:url: jdbc:mysql://192.168.184.135:3306/quartzdb?characterEncoding=utf-8&useUnicode=true&useSSL=falsedriver-class-name: com.mysql.jdbc.Driver # mysql8.0以前使用com.mysql.jdbc.Driverusername: rootpassword: 123456platform: mysql#通過這句配置將druid連接池引入到我們的配置中,spring會盡可能判斷類型是什么,然后根據情況去匹配驅動類。type: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 5 # 初始化大小min-idle: 5 # 最小max-active: 100 # 最大max-wait: 60000 # 配置獲取連接等待超時的時間time-between-eviction-runs-millis: 60000 # 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒min-evictable-idle-time-millis: 300000 # 指定一個空閑連接最少空閑多久后可被清除,單位是毫秒validationQuery: select 'x'test-while-idle: true # 當連接空閑時,是否執行連接測試test-on-borrow: false # 當從連接池借用連接時,是否測試該連接test-on-return: false # 在連接歸還到連接池時是否測試該連接filters: config,wall,stat # 配置監控統計攔截的filters,去掉后監控界面sql無法統計,'wall'用于防火墻poolPreparedStatements: true # 打開PSCache,并且指定每個連接上PSCache的大小maxPoolPreparedStatementPerConnectionSize: 20maxOpenPreparedStatements: 20# 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄connectionProperties: druid.stat.slowSqlMillis=200;druid.stat.logSlowSql=true;config.decrypt=false# 合并多個DruidDataSource的監控數據#use-global-data-source-stat: true#WebStatFilter配置,說明請參考Druid Wiki,配置_配置WebStatFilterweb-stat-filter:enabled: true #是否啟用StatFilter默認值trueurl-pattern: /*exclusions: /druid/*,*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.icosession-stat-enable: truesession-stat-max-count: 10#StatViewServlet配置,說明請參考Druid Wiki,配置_StatViewServlet配置stat-view-servlet:enabled: true #是否啟用StatViewServlet默認值trueurl-pattern: /druid/*reset-enable: truelogin-username: adminlogin-password: adminquartz.properties配置文件
#調度標識名 集群中每一個實例都必須使用相同的名稱 org.quartz.scheduler.instanceName = quartzScheduler #調度器實例編號自動生成,每個實例不能不能相同 org.quartz.scheduler.instanceId = AUTO #開啟分布式部署,集群 org.quartz.jobStore.isClustered = true #分布式節點有效性檢查時間間隔,單位:毫秒,默認值是15000 org.quartz.jobStore.clusterCheckinInterval = 2000 #遠程管理相關的配置,全部關閉 org.quartz.scheduler.rmi.export: false org.quartz.scheduler.rmi.proxy: false org.quartz.scheduler.wrapJobExecutionInUserTransaction: false #實例化ThreadPool時,使用的線程類為SimpleThreadPool(一般使用SimpleThreadPool即可滿足幾乎所有用戶的需求) org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool ##并發個數,指定線程數,至少為1(無默認值)(一般設置為1-100之間的的整數合適) org.quartz.threadPool.threadCount = 10 ##設置線程的優先級(最大為java.lang.Thread.MAX_PRIORITY 10,最小為Thread.MIN_PRIORITY 1,默認為5) org.quartz.threadPool.threadPriority = 5 #org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true #容許的最大作業延長時間,最大能忍受的觸發超時時間,如果超過則認為“失誤”,不敢再內存中還是數據中都要配置 org.quartz.jobStore.misfireThreshold = 6000 #持久化方式配置 # 默認存儲在內存中,保存job和Trigger的狀態信息到內存中的類 #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore #數據庫方式 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX #持久化方式配置數據驅動,MySQL數據庫 org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate #quartz相關數據表前綴名 org.quartz.jobStore.tablePrefix = QRTZ_#數據庫別名 隨便取 #org.quartz.jobStore.dataSource = qzDS #org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver #org.quartz.dataSource.qzDS.URL = jdbc:mysql://192.168.184.135:3306/quartzdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8 #org.quartz.dataSource.qzDS.user = root #org.quartz.dataSource.qzDS.password = 123456 #org.quartz.dataSource.qzDS.maxConnections = 10 #org.quartz.dataSource.qzDS.acquireIncrement=1///分割一下///
我這里使用的是MySql數據庫,想要使用Oracle數據庫,導入表(@"/路徑/tables_oracle.sql"),不管你怎么導,只要能用就行,在數據源的地方修改下連接信息,修改quartz.properties文件修改為如下,直接啟動就行了
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
///分割一下///
案例結構
模擬任務調度service層的業務邏輯
UserService.java
package com.quartz.service;import java.io.Serializable;public interface UserService extends Serializable {void getUserInfo();void getUserAddr(); }UserServiceImpl.java
package com.quartz.service.impl;import com.quartz.service.UserService; import org.springframework.stereotype.Service;@Service public class UserServiceImpl implements UserService {@Overridepublic void getUserInfo() {System.err.println("調度getUserInof成功");}@Overridepublic void getUserAddr() {System.err.println("調度getUserAddr成功");} }任務
JobOne.java
package com.quartz.job;import com.quartz.service.UserService; import org.quartz.DisallowConcurrentExecution; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.stereotype.Component;@Component @DisallowConcurrentExecution //保證上一次任務執行完畢再執行下一任務 //@PersistJobDataAfterExecution //上一個任務完成前寫入需要被下一個任務獲取的變量以及對應的屬性值,類似求和累加 public class JobOne extends QuartzJobBean {private UserService userService;@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {userService.getUserInfo();}public void setUserService(UserService userService) {this.userService = userService;} }JobTwo.java
package com.quartz.job;import com.quartz.service.UserService; import org.quartz.DisallowConcurrentExecution; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.stereotype.Component;@Component @DisallowConcurrentExecution public class JobTwo extends QuartzJobBean {//不能使用注入的方式,只能使用DateMap方式傳入參數private UserService userService;@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {userService.getUserAddr();}public void setUserService(UserService userService) {this.userService = userService;} }JobConfig.java
package com.quartz.jobconfig;import com.quartz.job.JobOne; import com.quartz.job.JobTwo; import com.quartz.service.UserService; import org.quartz.JobDataMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean;@Configuration public class JobConfig {@Autowiredprivate UserService userService;@Bean("jobOneDetail")public JobDetailFactoryBean jobOneDetailFactoryBean(JobOne jobOne) {JobDetailFactoryBean jobDetailFactoryBean =new JobDetailFactoryBean();jobDetailFactoryBean.setJobClass(jobOne.getClass());//沒有綁定觸發器仍然保留在Quartz的JobStore中jobDetailFactoryBean.setDurability(true);jobDetailFactoryBean.setName("jobOneDetailName");jobDetailFactoryBean.setGroup("jobOneDetailGroup");JobDataMap jobDataMap = new JobDataMap ();jobDataMap.put ("userService",userService);jobDetailFactoryBean.setJobDataMap(jobDataMap) ;return jobDetailFactoryBean;}@Bean("jobOneTrigger")public CronTriggerFactoryBean cronTriggerOneFactoryBean(@Qualifier("jobOneDetail") JobDetailFactoryBean jobDetailFactoryBean){CronTriggerFactoryBean cronTriggerFactoryBean=new CronTriggerFactoryBean();cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());cronTriggerFactoryBean.setCronExpression("*/1 * * * * ?");cronTriggerFactoryBean.setName("jobOneTriggerName");cronTriggerFactoryBean.setGroup("jobOneTriggerGroup");return cronTriggerFactoryBean;}@Bean("jobTwoDetail")public JobDetailFactoryBean jobTwoDetailFactoryBean(JobTwo jobTwo) {JobDetailFactoryBean jobDetailFactoryBean =new JobDetailFactoryBean();jobDetailFactoryBean.setJobClass(jobTwo.getClass());jobDetailFactoryBean.setDurability(true);jobDetailFactoryBean.setName("jobTwoDetailName");jobDetailFactoryBean.setGroup("jobTwoDetailGroup");JobDataMap jobDataMap = new JobDataMap ();jobDataMap.put ("userService",userService);jobDetailFactoryBean.setJobDataMap(jobDataMap) ;return jobDetailFactoryBean;}@Bean("jobTwoTrigger")public CronTriggerFactoryBean cronTriggerTwoFactoryBean(@Qualifier("jobTwoDetail") JobDetailFactoryBean jobDetailFactoryBean){CronTriggerFactoryBean cronTriggerFactoryBean=new CronTriggerFactoryBean();cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());cronTriggerFactoryBean.setCronExpression("*/1 * * * * ?");cronTriggerFactoryBean.setName("jobTwoTriggerName");cronTriggerFactoryBean.setGroup("jobTwoTriggerGroup");return cronTriggerFactoryBean;}}SchedulerConfig.java
package com.quartz.jobconfig;import com.alibaba.druid.pool.DruidDataSource; import org.quartz.Trigger; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.quartz.SchedulerFactoryBean;@Configuration public class SchedulerConfig {//執行任務。有了觸發器,我們就可以執行任務了。注冊一個SchedulerFactroyBean,然后將觸發器一list的方式傳入@Beanpublic SchedulerFactoryBean schedulerFactoryBean(DruidDataSource druidDataSource, @Qualifier("jobOneTrigger") Trigger jobOneTrigger, @Qualifier("jobTwoTrigger") Trigger jobTwoTrigger){SchedulerFactoryBean schedulerFactoryBean=new SchedulerFactoryBean();//調度器名稱schedulerFactoryBean.setSchedulerName("TestScheduler");//數據源schedulerFactoryBean.setDataSource(druidDataSource);//覆蓋已存在的任務,用于Quartz集群,QuartzScheduler啟動會更新已存在的JobschedulerFactoryBean.setOverwriteExistingJobs(true);//延時1s啟動定時任務,避免系統未完全啟動卻開始執行定時任務的情況schedulerFactoryBean.setStartupDelay(1);//設置加載的quartz.properties配置文件schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));//自動啟動schedulerFactoryBean.setAutoStartup(true);//注冊觸發器schedulerFactoryBean.setTriggers(jobOneTrigger,jobTwoTrigger);return schedulerFactoryBean;} }啟動兩個改下端口8080,8081就行了,看到效負載調度。
節點爭搶Job問題
因為Quartz使用了一個隨機的負載均衡算法, Job以隨機的方式由不同的實例執行。Quartz官網上提到當前,還不存在一個方法來指派(釘住) 一個 Job 到集群中特定的節點。
參考鏈接:https://blog.csdn.net/qq_39669058/article/details/90411497
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Springboot整合Quartz集群部署以及配置Druid数据源的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字符串、数组、集合在使用时出现空指针怎么
- 下一篇: SpringBoot之AOP详解