1. XXL-JOB簡介
XXL-JOB是一個分布式任務(wù)調(diào)度平臺,其核心設(shè)計目標是開發(fā)迅速、學(xué)習(xí)簡單、輕量級、易擴展。現(xiàn)已開放源代碼并接入多家公司線上產(chǎn)品線,開箱即用。它的有兩個核心模塊,一個模塊叫做調(diào)度中心,另外一個模塊叫做執(zhí)行器,它把任務(wù)調(diào)度和任務(wù)執(zhí)行分成兩個部分。這樣調(diào)度模塊只需要負責(zé)任務(wù)的調(diào)度屬性,觸發(fā)調(diào)度信號。執(zhí)行模塊只需要接收調(diào)度信號,去執(zhí)行具體的業(yè)務(wù)邏輯,兩者可以各自的進行擴容和縮容。圖1是一張來自官方的架構(gòu)圖。
2. XXL-JOB搭建
既然是一個分布式調(diào)度平臺,肯定會有一個調(diào)度中心,當(dāng)然執(zhí)行器(被調(diào)度者)也是必不可少的,可以參考架構(gòu)圖。所以,使用xxl-job搭建一個demo,也必須有兩個端,下面本文分別從準備工作、搭建“調(diào)度中心”、搭建“執(zhí)行器”三個部分進行說明。
2.1 準備工作
2.1.1 下載源碼
源碼地址:https://github.com/xuxueli/xxl-job
我使用的源碼是2.2.0版本,這是目前最新的release版本。
源碼包含了文檔(數(shù)據(jù)庫初始化腳本、官方文檔、架構(gòu)圖等)、調(diào)度中心源碼、核心core、各個版本的執(zhí)行器源碼。如圖2所示:
2.1.2 數(shù)據(jù)庫準備
數(shù)據(jù)庫腳本在doc路徑下,將其執(zhí)行之后可以創(chuàng)建一個數(shù)據(jù)庫,如圖3所示:
2.2 搭建調(diào)度中心
2.2.1 配置調(diào)度中心
將數(shù)據(jù)庫連接信息和報警信息配置成自己的,配置文件如下:
### web
server.port=8080
server.servlet.context-path=/xxl-job-admin
### actuator
management.server.servlet.context-path=/actuator
management.health.mail.enabled=false
### resources
spring.mvc.servlet.load-on-startup=0
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
### freemarker
spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########
### mybatis
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
#mybatis.type-aliases-package=com.xxl.job.admin.core.model
### xxl-job, datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
### datasource-pool
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=HikariCP
spring.datasource.hikari.max-lifetime=900000
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.connection-test-query=SELECT 1
### xxl-job, email
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
### xxl-job, access token
xxl.job.accessToken=
### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
xxl.job.i18n=zh_CN
## xxl-job, triggerpool max size
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100
### xxl-job, log retention days
xxl.job.logretentiondays=30
2.2.2 啟動調(diào)度中心
在IDEA里面直接運行,如果使用的是macOS系統(tǒng)的話,可能會出現(xiàn)錯誤:Failed to create parent directories for [/data/applogs/xxl-job/xxl-job-admin.log],如圖4所示:
解決辦法是:將logback.xml中的“/data/applogs/xxl-job/xxl-job-admin.log”改為“./data/applogs/xxl-job/xxl-job-admin.log”,如圖5所示。后續(xù)在測試運行的時候,執(zhí)行器端會拋出類似異常,用同樣的方式可以解決。
啟動之后瀏覽器訪問http://localhost:8080/xxl-job-admin,使用默認的用戶名(admin)和密碼(123456)登陸之后,可以看到如圖6所示頁面:
2.3 搭建“執(zhí)行器”
2.3.1 新建執(zhí)行器項目
使用IDEA新建一個Spring Boot項目:xxl-job-executor
2.3.2 添加相關(guān)依賴和配置執(zhí)行器
Maven依賴:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.2.0</version>
</dependency>
主要需要配置xxl-job的調(diào)度中心地址信息、xxl-job執(zhí)行器相關(guān)信息。配置文件如下:
# web port
server.port=8081
# no web
#spring.main.web-environment=false
# log config
logging.config=classpath:logback.xml
### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### xxl-job, access token
xxl.job.accessToken=
### xxl-job executor appname
xxl.job.executor.appname=xxl-job-executor-test
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=9999
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30
還要創(chuàng)建一個XxlJobConfig.java配置執(zhí)行器。代碼如下:
@Configuration
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@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;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.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;
}
}
當(dāng)然還要添加logback.xml文件。
2.3.3 編寫執(zhí)行器
- 在Spring Bean實例中,開發(fā)Job方法,方式格式要求為 "public ReturnT<String> execute(String param)"
- 為Job方法添加注解 "@XxlJob(value="自定義jobhandler名稱", init = "JobHandler初始化方法", destroy = "JobHandler銷毀方法")",注解value值對應(yīng)的是調(diào)度中心新建任務(wù)的JobHandler屬性的值。之前的2.1.0版本中不支持在方法上面添加注解,需要在類上面添加@JobHandler注解,并繼承IJobHandler。
- 執(zhí)行日志:需要通過 "XxlJobLogger.log" 打印執(zhí)行日志;
代碼如下:
@Component
public class TestXxlJobHandler {
private static Logger logger = LoggerFactory.getLogger(TestXxlJobHandler.class);
/**
* 1、簡單任務(wù)示例(Bean模式)
*/
@XxlJob("testJobHandler")
public ReturnT<String> demoJobHandler(String param) throws Exception {
System.out.println(new Date() + "Test Xxl-Job~");
return ReturnT.SUCCESS;
}
}
完成之后的整個代碼結(jié)構(gòu)如圖8所示:
3. 測試
在本機運行調(diào)度中心和執(zhí)行器。
3.1 新增執(zhí)行器
在調(diào)度中心新增一個測試執(zhí)行器,AppName為xxl-job-executor-test,名稱為測試執(zhí)行器,注冊方式選擇自行注冊即可,如圖9所示:
3.2 新增任務(wù)
3.2.1 新增任務(wù)
新增一個任務(wù),名稱與代碼中名稱一致,配置為每2分鐘執(zhí)行一次,路由策略為一致性HASH,運行模式為BEAN,阻塞處理策略為單機串行,配置如圖10所示:
3.2.2 配置屬性
詳細配置屬性可以參考:
● 執(zhí)行器:任務(wù)的綁定的執(zhí)行器,任務(wù)觸發(fā)調(diào)度時將會自動發(fā)現(xiàn)注冊成功的執(zhí)行器, 實現(xiàn)任務(wù)自動發(fā)現(xiàn)功能; 另一方面也可以方便的進行任務(wù)分組。每個任務(wù)必須綁定一個執(zhí)行器, 可在 "執(zhí)行器管理" 進行設(shè)置;
● 任務(wù)描述:任務(wù)的描述信息,便于任務(wù)管理;
● 路由策略:當(dāng)執(zhí)行器集群部署時,提供豐富的路由策略,包括;
FIRST(第一個):固定選擇第一個機器;
LAST(最后一個):固定選擇最后一個機器;
ROUND(輪詢):;
RANDOM(隨機):隨機選擇在線的機器;
CONSISTENT_HASH(一致性HASH):每個任務(wù)按照Hash算法固定選擇某一臺機器,且所有任務(wù)均勻散列在不同機器上。
LEAST_FREQUENTLY_USED(最不經(jīng)常使用):使用頻率最低的機器優(yōu)先被選舉;
LEAST_RECENTLY_USED(最近最久未使用):最久未使用的機器優(yōu)先被選舉;
FAILOVER(故障轉(zhuǎn)移):按照順序依次進行心跳檢測,第一個心跳檢測成功的機器選定為目標執(zhí)行器并發(fā)起調(diào)度;
BUSYOVER(忙碌轉(zhuǎn)移):按照順序依次進行空閑檢測,第一個空閑檢測成功的機器選定為目標執(zhí)行器并發(fā)起調(diào)度;
SHARDING_BROADCAST(分片廣播):廣播觸發(fā)對應(yīng)集群中所有機器執(zhí)行一次任務(wù),同時系統(tǒng)自動傳遞分片參數(shù);可根據(jù)分片參數(shù)開發(fā)分片任務(wù);
● Cron:觸發(fā)任務(wù)執(zhí)行的Cron表達式;
● 運行模式:
BEAN模式:任務(wù)以JobHandler方式維護在執(zhí)行器端;需要結(jié)合 "JobHandler" 屬性匹配執(zhí)行器中任務(wù);
GLUE模式(Java):任務(wù)以源碼方式維護在調(diào)度中心;該模式的任務(wù)實際上是一段繼承自IJobHandler的Java類代碼并 "groovy" 源碼方式維護,它在執(zhí)行器項目中運行,可使用@Resource/@Autowire注入執(zhí)行器里中的其他服務(wù);
GLUE模式(Shell):任務(wù)以源碼方式維護在調(diào)度中心;該模式的任務(wù)實際上是一段 "shell" 腳本;
GLUE模式(Python):任務(wù)以源碼方式維護在調(diào)度中心;該模式的任務(wù)實際上是一段 "python" 腳本;
GLUE模式(PHP):任務(wù)以源碼方式維護在調(diào)度中心;該模式的任務(wù)實際上是一段 "php" 腳本;
GLUE模式(NodeJS):任務(wù)以源碼方式維護在調(diào)度中心;該模式的任務(wù)實際上是一段 "nodejs" 腳本;
GLUE模式(PowerShell):任務(wù)以源碼方式維護在調(diào)度中心;該模式的任務(wù)實際上是一段 "PowerShell" 腳本;
● JobHandler:運行模式為 "BEAN模式" 時生效,對應(yīng)執(zhí)行器中新開發(fā)的JobHandler類“@JobHandler”注解自定義的value值;
● 阻塞處理策略:調(diào)度過于密集執(zhí)行器來不及處理時的處理策略;
單機串行(默認):調(diào)度請求進入單機執(zhí)行器后,調(diào)度請求進入FIFO隊列并以串行方式運行;
丟棄后續(xù)調(diào)度:調(diào)度請求進入單機執(zhí)行器后,發(fā)現(xiàn)執(zhí)行器存在運行的調(diào)度任務(wù),本次請求將會被丟棄并標記為失敗;
覆蓋之前調(diào)度:調(diào)度請求進入單機執(zhí)行器后,發(fā)現(xiàn)執(zhí)行器存在運行的調(diào)度任務(wù),將會終止運行中的調(diào)度任務(wù)并清空隊列,然后運行本地調(diào)度任務(wù);
● 子任務(wù):每個任務(wù)都擁有一個唯一的任務(wù)ID(任務(wù)ID可以從任務(wù)列表獲取),當(dāng)本任務(wù)執(zhí)行結(jié)束并且執(zhí)行成功時,將會觸發(fā)子任務(wù)ID所對應(yīng)的任務(wù)的一次主動調(diào)度。
● 任務(wù)超時時間:支持自定義任務(wù)超時時間,任務(wù)運行超時將會主動中斷任務(wù);
● 失敗重試次數(shù);支持自定義任務(wù)失敗重試次數(shù),當(dāng)任務(wù)失敗時將會按照預(yù)設(shè)的失敗重試次數(shù)主動進行重試;
● 報警郵件:任務(wù)調(diào)度失敗時郵件通知的郵箱地址,支持配置多郵箱地址,配置多個郵箱地址時用逗號分隔;
● 負責(zé)人:任務(wù)的負責(zé)人;
● 執(zhí)行參數(shù):任務(wù)執(zhí)行所需的參數(shù);
3.3 啟動任務(wù)測試
啟動調(diào)度任務(wù),如圖11所示:
可以查看日志或者控制臺信息,運行結(jié)果滿意,如圖12所示:
在控制臺運行報表界面也可以看到調(diào)度和執(zhí)行情況,如圖13所示。圖中那一次調(diào)度失敗是由于執(zhí)行器重啟,造成了調(diào)度中心調(diào)度任務(wù)的時候發(fā)現(xiàn)調(diào)度地址為空,所以執(zhí)行失敗。
參考文檔:官方中文文檔