日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
使用SpringBoot+Quartz實現(xiàn)分布式定時任務(wù)平臺

一、分布式任務(wù)應(yīng)用場景

定時任務(wù)系統(tǒng)在應(yīng)用平臺中的重要性不言而喻,特別是互聯(lián)網(wǎng)電商、金融等行業(yè)更是離不開定時任務(wù)。在任務(wù)數(shù)量不多、執(zhí)行頻率不高時,單臺服務(wù)器完全能夠滿足。

十年的柯城網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。營銷型網(wǎng)站建設(shè)的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整柯城建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)從事“柯城網(wǎng)站設(shè)計”,“柯城網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。

但是隨著業(yè)務(wù)逐漸增加,定時任務(wù)系統(tǒng)必須具備高可用和水平擴(kuò)展的能力,單臺服務(wù)器已經(jīng)不能滿足需求。因此需要把定時任務(wù)系統(tǒng)部署到集群中,實現(xiàn)分布式定時任務(wù)系統(tǒng)集群。

Quartz的集群功能通過故障轉(zhuǎn)移和負(fù)載平衡功能為調(diào)度程序帶來高可用性和可擴(kuò)展性。

Quartz是通過數(shù)據(jù)庫表來存儲和共享任務(wù)信息的。獨立的Quartz節(jié)點并不與另一個節(jié)點或者管理節(jié)點通信,而是通過數(shù)據(jù)庫鎖機(jī)制來調(diào)度執(zhí)行定時任務(wù)。

需要注意的是,在集群環(huán)境下,時鐘必須同步,否則執(zhí)行時間不一致。

二、Quartz實現(xiàn)分布式定時任務(wù)

1. 添加Quartz依賴

首先,引入Quartz中提供分布式處理的JAR包以及數(shù)據(jù)庫和連接相關(guān)的依賴。示例代碼如下:


org.springframework.boot
spring-boot-starter-quartz




mysql
mysql-connector-java




org.springframework.boot
spring-boot-starter-data-jpa

在上面的示例中,除了添加Quartz依賴外,還需要添加mysql-connector-java和

spring-boot-starter-data-jpa兩個組件,這兩個組件主要用于JOB持久化到MySQL數(shù)據(jù)庫。

2. 初始化Quartz數(shù)據(jù)庫

分布式Quartz定時任務(wù)的配置信息存儲在數(shù)據(jù)庫中,數(shù)據(jù)庫初始化腳本可以在官方網(wǎng)站中查找,默認(rèn)保存在quartz-2.2.3-distribution\src\org\quartz\impl\jdbcjobstore\tables-mysql.sql目錄下。首先創(chuàng)建quartz_jobs數(shù)據(jù)庫,然后在數(shù)據(jù)庫中執(zhí)行tables-mysql.sql初始化腳本。具體示例如下:

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(200) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
(
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
(
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
(
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);

使用tables-mysql.sql創(chuàng)建表的語句執(zhí)行完成后,說明Quartz的數(shù)據(jù)庫和表創(chuàng)建成功,我們查看數(shù)據(jù)庫的ER圖,如下圖所示。

3. 配置數(shù)據(jù)庫和Quartz

修改application.properties配置文件,配置數(shù)據(jù)庫與Quartz。具體操作如下:

# server.port=8090
# Quartz 數(shù)據(jù)庫
spring.datasource.url=jdbc:mysql://localhost:3306/quartz_jobs?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.max-active=1000
spring.datasource.max-idle=20
spring.datasource.min-idle=5
spring.datasource.initial-size=10

# 是否使用properties作為數(shù)據(jù)存儲
org.quartz.jobStore.useProperties=false
# 數(shù)據(jù)庫中表的命名前綴
org.quartz.jobStore.tablePrefix=QRTZ_
# 是否是一個集群,是不是分布式的任務(wù)
org.quartz.jobStore.isClustered=true
# 集群檢查周期,單位為毫秒,可以自定義縮短時間。當(dāng)某一個節(jié)點宕機(jī)的時候,其他節(jié)點等待多久后開始執(zhí)行任務(wù)
org.quartz.jobStore.clusterCheckinInterval=5000
# 單位為毫秒,集群中的節(jié)點退出后,再次檢查進(jìn)入的時間間隔
org.quartz.jobStore.misfireThreshold=60000
# 事務(wù)隔離級別
org.quartz.jobStore.txIsolationLevelReadCommitted=true
# 存儲的事務(wù)管理類型
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
# 使用的Delegate類型
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 集群的命名,一個集群要有相同的命名
org.quartz.scheduler.instanceName=ClusterQuartz
# 節(jié)點的命名,可以自定義。AUTO代表自動生成
org.quartz.scheduler.instanceId=AUTO
# rmi遠(yuǎn)程協(xié)議是否發(fā)布
org.quartz.scheduler.rmi.export=false
# rmi遠(yuǎn)程協(xié)議代理是否創(chuàng)建
org.quartz.scheduler.rmi.proxy=false
# 是否使用用戶控制的事務(wù)環(huán)境觸發(fā)執(zhí)行任務(wù)
org.quartz.scheduler.wrapJobExecutionInUserTransaction=false

上面的配置主要是Quartz數(shù)據(jù)庫和Quartz分布式集群相關(guān)的屬性配置。分布式定時任務(wù)的配置存儲在數(shù)據(jù)庫中,所以需要配置數(shù)據(jù)庫連接和Quartz配置信息,為Quartz提供數(shù)據(jù)庫配置信息,如數(shù)據(jù)庫、數(shù)據(jù)表的前綴之類。

4. 定義定時任務(wù)

后臺定時任務(wù)與普通Quartz任務(wù)并無差異,只是增加了@

PersistJobDataAfterExecution注解和@DisallowConcurrentExecution注解。創(chuàng)建QuartzJob定時任務(wù)類并實現(xiàn)Quartz定時任務(wù)的具體示例代碼如下:

// 持久化
@PersistJobDataAfterExecution
// 禁止并發(fā)執(zhí)行
@DisallowConcurrentExecution
public class QuartzJob extends QuartzJobBean {
private static final Logger log = LoggerFactory.getLogger(QuartzJob.class);

@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
String taskName = context.getJobDetail().getJobDataMap().getString("name");
log.info("---> Quartz job, time:{"+new Date()+"} ,name:{"+taskName+"}<----");
}
}

在上面的示例中,創(chuàng)建了QuartzJob定時任務(wù)類,使用@

PersistJobDataAfterExecution注解持久化任務(wù)信息。DisallowConcurrentExecution禁止并發(fā)執(zhí)行,避免同一個任務(wù)被多次并發(fā)執(zhí)行。

5. SchedulerConfig配置

創(chuàng)建SchedulerConfig配置類,初始化Quartz分布式集群相關(guān)配置,包括集群設(shè)置、數(shù)據(jù)庫等。示例代碼如下:

@Configuration
public class SchedulerConfig {

@Autowired
private DataSource dataSource;

/**
* 調(diào)度器
*
* @return
* @throws Exception
*/
@Bean
public Scheduler scheduler() throws Exception {
Scheduler scheduler = schedulerFactoryBean().getScheduler();
return scheduler;
}

/**
* Scheduler工廠類
*
* @return
* @throws IOException
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setSchedulerName("Cluster_Scheduler");
factory.setDataSource(dataSource);
factory.setApplicationContextSchedulerContextKey("applicationContext");
factory.setTaskExecutor(schedulerThreadPool());
//factory.setQuartzProperties(quartzProperties());
factory.setStartupDelay(10);// 延遲10s執(zhí)行
return factory;
}

/**
* 配置Schedule線程池
*
* @return
*/
@Bean
public Executor schedulerThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors());
executor.setQueueCapacity(Runtime.getRuntime().availableProcessors());
return executor;
}
}

在上面的示例中,主要是配置Schedule線程池、配置Quartz數(shù)據(jù)庫、創(chuàng)建Schedule調(diào)度器實例等初始化配置。

6. 觸發(fā)定時任務(wù)

配置完成之后,還需要觸發(fā)定時任務(wù),創(chuàng)建JobStartupRunner類以便在系統(tǒng)啟動時觸發(fā)所有定時任務(wù)。示例代碼如下:

@Component
public class JobStartupRunner implements CommandLineRunner {
@Autowired
SchedulerConfig schedulerConfig;
private static String TRIGGER_GROUP_NAME = "test_trigger";
private static String JOB_GROUP_NAME = "test_job";

@Override
public void run(String... args) throws Exception {
Scheduler scheduler;
try {
scheduler = schedulerConfig.scheduler();
TriggerKey triggerKey = TriggerKey.triggerKey("trigger1", TRIGGER_GROUP_NAME);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (null == trigger) {
Class clazz = QuartzJob.class;
JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity("job1", JOB_GROUP_NAME).usingJobData("name","weiz QuartzJob").build();
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");
trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", TRIGGER_GROUP_NAME)
.withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("Quartz 創(chuàng)建了job:...:" + jobDetail.getKey());
} else {
System.out.println("job已存在:{}" + trigger.getKey());
}

TriggerKey triggerKey2 = TriggerKey.triggerKey("trigger2", TRIGGER_GROUP_NAME);
CronTrigger trigger2 = (CronTrigger) scheduler.getTrigger(triggerKey2);
if (null == trigger2) {
Class clazz = QuartzJob2.class;
JobDetail jobDetail2 = JobBuilder.newJob(clazz).withIdentity("job2", JOB_GROUP_NAME).usingJobData("name","weiz QuartzJob2").build();
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");
trigger2 = TriggerBuilder.newTrigger().withIdentity("trigger2", TRIGGER_GROUP_NAME)
.withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail2, trigger2);
System.out.println("Quartz 創(chuàng)建了job:...:{}" + jobDetail2.getKey());
} else {
System.out.println("job已存在:{}" + trigger2.getKey());
}
scheduler.start();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}

在上面的示例中,為了適應(yīng)分布式集群,我們在系統(tǒng)啟動時觸發(fā)定時任務(wù),判斷任務(wù)是否已經(jīng)創(chuàng)建、是否正在執(zhí)行。如果集群中的其他示例已經(jīng)創(chuàng)建了任務(wù),則啟動時無須觸發(fā)任務(wù)。

三、 驗證測試

配置完成之后,接下來啟動任務(wù),測試分布式任務(wù)配置是否成功。啟動一個實例,可以看到定時任務(wù)執(zhí)行了,然后每10秒鐘打印輸出一次,如下圖所示。

接下來,模擬分布式部署的情況。我們再啟動一個測試程序?qū)嵗?,這樣就有兩個后臺定時任務(wù)實例。

實例1:

實例2:

從上面的日志中可以看到,Quartz Job和Quartz Job2交替地在兩個任務(wù)實例進(jìn)程中執(zhí)行,同一時刻同一個任務(wù)只有一個進(jìn)程在執(zhí)行,這說明已經(jīng)達(dá)到了分布式后臺定時任務(wù)的效果。

接下來,停止任務(wù)實例1,測試任務(wù)實例2是否會接管所有任務(wù)繼續(xù)執(zhí)行。如圖10-11所示,停止任務(wù)實例1后,任務(wù)實例2接管了所有的定時任務(wù)。這樣如果集群中的某個實例異常了,其他實例能夠接管所有的定時任務(wù),確保任務(wù)集群的穩(wěn)定運行。

最后

以上,我們就把Spring Boot集成Quartz實現(xiàn)分布式定時任務(wù)的功能介紹完了。分布式定時任務(wù)在應(yīng)用開發(fā)中非常重要的功能模塊,希望大家能夠熟練掌握。


分享題目:使用SpringBoot+Quartz實現(xiàn)分布式定時任務(wù)平臺
當(dāng)前地址:http://m.5511xx.com/article/cojsoho.html