【需求】
SpringBoot項(xiàng)目,接入定時(shí)任務(wù)平臺(tái)xxl-job。
支持集群環(huán)境下定時(shí)任務(wù)/腳本任務(wù)/手動(dòng)觸發(fā)任務(wù)的統(tǒng)一注冊(cè)和管理,并且支持?jǐn)?shù)據(jù)的分片處理的功能。
【介紹】
大眾點(diǎn)評(píng)員工徐雪里于2015年發(fā)布的分布式任務(wù)調(diào)度平臺(tái),是一個(gè)輕量級(jí)分布式任務(wù)調(diào)度框架,其核心設(shè)計(jì)目標(biāo)是開發(fā)迅速、學(xué)習(xí)簡單、輕量級(jí)、易擴(kuò)展。
● 有web界面,通過網(wǎng)頁進(jìn)行任務(wù)注冊(cè),并可以動(dòng)態(tài)編輯、啟動(dòng)、終止
● 調(diào)度中心是中心化部署,但支持集群部署來保證高可用
● 執(zhí)行器的HA
執(zhí)行器是分布式任務(wù)執(zhí)行的基本單元,支持集群部署??梢岳斫獬梢粋€(gè)微服務(wù)是一個(gè)執(zhí)行器,executor.appname相同的執(zhí)行器組成了一個(gè)執(zhí)行器集群,執(zhí)行器在系統(tǒng)啟動(dòng)時(shí)自動(dòng)注冊(cè)到調(diào)度中心。
調(diào)度中心根據(jù)配置好的定時(shí)參數(shù),使用合適的路由策略從執(zhí)行器集群中選擇指定的執(zhí)行器進(jìn)行任務(wù)的執(zhí)行,集群部署保證定時(shí)任務(wù)的HA
● 執(zhí)行器的動(dòng)態(tài)分片
執(zhí)行器集群部署時(shí),任務(wù)路由策略選擇”分片廣播”情況下,一次任務(wù)調(diào)度將會(huì)廣播觸發(fā)對(duì)應(yīng)集群中所有執(zhí)行器執(zhí)行一次任務(wù),同時(shí)系統(tǒng)自動(dòng)傳遞分片參數(shù);可根據(jù)分片參數(shù)開發(fā)分片任務(wù);
“分片廣播” 以執(zhí)行器為維度進(jìn)行分片,支持動(dòng)態(tài)擴(kuò)容“執(zhí)行器集群”從而動(dòng)態(tài)增加分片數(shù)量,協(xié)同進(jìn)行業(yè)務(wù)處理;在進(jìn)行大數(shù)據(jù)量業(yè)務(wù)操作時(shí)可顯著提升任務(wù)處理能力和速度。
“分片廣播” 和普通任務(wù)開發(fā)流程一致,不同之處在于可以獲取分片參數(shù)進(jìn)行分片業(yè)務(wù)處理。
適用場景
○ 分片任務(wù)場景:10個(gè)執(zhí)行器的集群來處理10w條數(shù)據(jù),每臺(tái)機(jī)器只需要處理1w條數(shù)據(jù),耗時(shí)降低10倍;
○ 廣播任務(wù)場景:廣播執(zhí)行器機(jī)器運(yùn)行shell腳本、廣播集群節(jié)點(diǎn)進(jìn)行緩存更新等
【BEAN模式開發(fā)】
||? 下載源碼并解壓
||? 在指定的數(shù)據(jù)庫中,執(zhí)行數(shù)據(jù)庫初始化SQL腳本,腳本位置為項(xiàng)目根目錄文件夾的doc/db/tables_xxl_job.sql
||? 按maven格式將源碼導(dǎo)入IDE, 修改調(diào)度中心的配置文件,指定DB配置信息,配置文件的地址是xxl-job-admin\src\main\resources\application.properties。 在配置文件中還可以配置報(bào)警的發(fā)件郵箱信息等參數(shù)。
||? 項(xiàng)目編譯,打包,部署在docker容器中,并配置訪問
||? 瀏覽器打開http://{ip}:{port}/xxl-job-admin訪問調(diào)度中心,默認(rèn)登錄賬號(hào)為admin/123456,可登錄后修改密碼
||? SpringBoot項(xiàng)目導(dǎo)入依賴
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.2.0</version>
</dependency>
||? SpringBoot項(xiàng)目核心模塊(common-core)配置xxl-job
@Slf4j
@Configuration
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
/**
* 將執(zhí)行器組件交給spring管理
*/
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
/**
* 針對(duì)多網(wǎng)卡、容器內(nèi)部署等情況,可借助 "spring-cloud-commons" 提供的 "InetUtils" 組件靈活定制注冊(cè)IP;
*
* 1、引入依賴:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器啟動(dòng)變量
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3、獲取IP
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/
}
||? 啟動(dòng)類導(dǎo)入配置文件
@SpringBootApplication
@Import({XxlJobConfig.class})
public class UserApplication {
……
}
||? 編寫JobHandler
@Slf4j
@Component
public class MyXxlJobHandler {
/**
* 執(zhí)行器的第一個(gè)任務(wù)對(duì)應(yīng)的執(zhí)行方法
*/
@XxlJob("FirstTaskHandler")
public ReturnT<String> teskExecute1(String param) {
……
return ReturnT.SUCCESS;
}
/**
* 執(zhí)行器的第二個(gè)任務(wù)對(duì)應(yīng)的執(zhí)行方法
*/
@XxlJob("SecondTaskHandler")
public ReturnT<String> teskExecute2(String param) {
……
return ReturnT.SUCCESS;
}
}
||? application.yaml配置xxl-job
xxl:
job:
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin # [選填]調(diào)度中心地址(以本地為例),執(zhí)行器將會(huì)使用該地址進(jìn)行"執(zhí)行器心跳注冊(cè)"和"任務(wù)結(jié)果回調(diào)";若調(diào)度中心集群部署存在多個(gè)地址則用逗號(hào)分隔,為空則關(guān)閉自動(dòng)注冊(cè)
executor:
# [選填] 執(zhí)行器注冊(cè)優(yōu)先使用該配置作為注冊(cè)地址,為空時(shí)使用內(nèi)嵌服務(wù) ”IP:PORT“ 作為注冊(cè)地址。從而更靈活的支持容器類型執(zhí)行器動(dòng)態(tài)IP和動(dòng)態(tài)映射端口問題。
address:
# [選填] 執(zhí)行器名稱;為空則關(guān)閉自動(dòng)注冊(cè)
appname: my-handler
# [選填] 執(zhí)行器IP,默認(rèn)為空表示自動(dòng)獲取IP,多網(wǎng)卡時(shí)可手動(dòng)設(shè)置指定IP,該IP不會(huì)綁定Host僅作為通訊使用;地址信息用于 "執(zhí)行器注冊(cè)" 和 "調(diào)度中心請(qǐng)求并觸發(fā)任務(wù)"
ip:
# [選填] 執(zhí)行器端口,≤0則自動(dòng)獲取,默認(rèn)端口為9999,單機(jī)部署多個(gè)執(zhí)行器時(shí),注意要配置不同執(zhí)行器端口;
port: 9999
# [選填] 執(zhí)行器運(yùn)行日志文件存儲(chǔ)磁盤路徑:需對(duì)該路徑擁有讀寫權(quán)限;為空則使用默認(rèn)路徑
logpath: /data/applogs/xxl-job/jobhandler
# [選填] 執(zhí)行器日志文件保存天數(shù):過期日志自動(dòng)清理, 限制值≥3時(shí)生效; 否則(如-1), 關(guān)閉自動(dòng)清理功能
logretentiondays: 30
# [選填] 執(zhí)行器騰訊TOKEN,非空時(shí)啟用
accessToken:
||? (可選)執(zhí)行器集群配置:執(zhí)行器支持集群部署,提升調(diào)度系統(tǒng)可用性,同時(shí)提升任務(wù)處理能力。要求如下:
1.執(zhí)行器回調(diào)地址(xxl.job.admin.addresses)需要保持一致;執(zhí)行器根據(jù)該配置進(jìn)行執(zhí)行器自動(dòng)注冊(cè)等操作。
2.同一個(gè)執(zhí)行器集群內(nèi)AppName(xxl.job.executor.appname)需保持一致;調(diào)度中心根據(jù)該配置動(dòng)態(tài)發(fā)現(xiàn)不同集群的在線執(zhí)行器列表。
||? 啟動(dòng)SpringBoot項(xiàng)目
||? 登錄xxl-job控制臺(tái): http://IP:端口/xxl-job-admin/(以本地為例可以登錄服務(wù)器),賬號(hào)admin,密碼123456
||? 執(zhí)行器管理>新增執(zhí)行器

? AppName:和xxl.job.executor.appname(my-handler)保持一致
? 名稱:自定義,簡述執(zhí)行器功能即可
? 注冊(cè)方式:選自動(dòng)注冊(cè),注冊(cè)完成后,看到執(zhí)行器列表,自動(dòng)多了一條在線機(jī)器地址。

||? 任務(wù)管理>新建任務(wù)

? 執(zhí)行器:自動(dòng)對(duì)應(yīng)剛剛新建執(zhí)行器時(shí)的功能簡述
? 任務(wù)描述:詳述該執(zhí)行器所執(zhí)行的任務(wù)
? Cron:定時(shí)設(shè)置
? JobHandler:手動(dòng)輸入和@XxlJob注解對(duì)應(yīng)的value值(FirstTaskHandler、SecondTaskHandler)
? 報(bào)警郵件可填開發(fā)/運(yùn)維人員的郵箱地址。
? 任務(wù)參數(shù)(可選):Handler方法可通過param接收
||? 新增任務(wù)成功,操作欄將按鈕選擇為“啟動(dòng)”

||? 手動(dòng)執(zhí)行一次任務(wù),看到控制臺(tái)打印成功:

備注:"NJU,Happy 120th Birthday~"是我們?cè)谌蝿?wù)中傳過去的參數(shù)
【GLUE模式開發(fā)】
介紹
剛才選擇的是Bean模式,利用Spring環(huán)境中寫好的Bean執(zhí)行任務(wù);
還有一種是GLUE模式,將任務(wù)以源碼形式,在調(diào)度中心實(shí)時(shí)維護(hù):
||? 新增任務(wù),選擇我們剛剛的執(zhí)行器,新增任務(wù)
“運(yùn)行模式”選擇“GLUE(Java)”,
“阻塞處理策略”選擇單機(jī)串行,
“JobHandler”可以不選擇

然后選擇右邊的“GLUDE IDE”,編輯可在單獨(dú)中心實(shí)時(shí)維護(hù)的任務(wù):

||? 手動(dòng)執(zhí)行一次任務(wù),并傳入?yún)?shù):“My name is Harry~”

||? 執(zhí)行成功:

【分片廣播&動(dòng)態(tài)分片】
介紹
執(zhí)行器集群部署時(shí),任務(wù)路由策略選擇”分片廣播”情況下,一次任務(wù)調(diào)度將會(huì)廣播觸發(fā)集群中所有執(zhí)行器執(zhí)行一次任務(wù),同時(shí)系統(tǒng)自動(dòng)傳遞分片參數(shù);可根據(jù)分片參數(shù)開發(fā)分片任務(wù)。
“分片廣播” 以執(zhí)行器為維度進(jìn)行分片,支持動(dòng)態(tài)擴(kuò)容“執(zhí)行器集群”,從而動(dòng)態(tài)增加分片數(shù),協(xié)同處理業(yè)務(wù);在操作大數(shù)據(jù)量業(yè)務(wù)時(shí)可顯著提升處理能力和速度。
“分片廣播” 和普通任務(wù)開發(fā)流程一致,不同之處在于可以獲取分片參數(shù),獲取分片參數(shù)進(jìn)行分片業(yè)務(wù)處理。
? Java語言任務(wù)獲取分片參數(shù)方式:BEAN、GLUE模式(Java)
// 可參考Sample示例執(zhí)行器中的示例任務(wù)"ShardingJobHandler"了解試用
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
? 腳本語言任務(wù)獲取分片參數(shù)方式:GLUE模式(Shell)、GLUE模式(Python)、GLUE模式(Nodejs)
// 腳本任務(wù)入?yún)⒐潭槿齻€(gè),依次為:任務(wù)傳參、分片序號(hào)、分片總數(shù)。以
Shell模式任務(wù)為例,獲取分片參數(shù)代碼如下
echo "分片序號(hào) index = $2"
echo "分片總數(shù) total = $3"
分片參數(shù)屬性說明:
? index:當(dāng)前分片序號(hào)(從0開始),執(zhí)行器集群列表中當(dāng)前執(zhí)行器的序號(hào);
? total:總分片數(shù),執(zhí)行器集群的總機(jī)器數(shù)量;