什么是任務調度
什么是任務調度?某一時間段進行任務的操作。
具體任務調度有哪些應用的場景?數據同步、交易信息、清除用戶的信息、定期發送報表數據、活動推送等。
傳統實現定時任務的方式?Thread、TimeTask、ScheduleExecutorService、Quartz 等;不過,這幾種方式都是在單點系統使用,一旦Job服務器宕機之后,就必須采取一些措施;具體操作如下:
(1) 使用心跳檢測監控自動重啟、任務補償機制(任務做標記)
(2) 定時任務在執行代碼的時候中間突然報錯,使用日志記錄錯誤,跳過繼續執行,在使用定時Job 掃描日志錯誤記錄,進行補償信息。
(3) 定時Job 在執行的時候,導致整個 Job 異常結束掉,發送郵件通知給運維人員。
分布式定時任務的方式?XXL-Job、Elastic-job等。不過,既然采用分布式,那么肯定會遇到項目部署集群,導致任務重復執行多次;具體操作如下:
(1) Zookeeper 實現分布式鎖,每次保證拿到鎖再執行,效率比較低。
(2) 配置文件中加入定時任務的開關,但是只能保證一台服務器執行,變為單擊服務器。
(3) 啟動的時候使用數據庫唯一標識;同樣是效率低。
(4) 分布式調度任務平台,解決了任務冪等問題,Job 負載均衡輪詢機制(推薦)。
那么現在我們來總結下,首先傳統的定時任務,幾乎無法做到高可用,再加上項目部署集群,會導致任務冪等性問題;此時分布式定時任務調度平台便發揮了作用,咱們拿 XXL-Job 來進行說明;相關作用如下:
(1) 支持Job集群,Job 負載均衡輪詢機制保證冪等性問題。
(2) 支持Job補償,如果Job執行失敗的話,會自動實現重試機制,超過重啟次數后,會發送郵件通知運維人員。
(3) 支持Job日志記錄。
(4) 動態配置定時規則,傳統定時Job觸發規則都是寫死在代碼中。
XXL-JOB簡介
開源社區:https://www.xuxueli.com/xxl-job/
環境:
Maven3+
Jdk1.8+
Mysql5.7+
xxl-job執行原理
調度平台、執行器、任務管理,相關解釋如下:
- 調度平台:統一管理任務調度的平台,負責轉發任務到對應的執行服務器。
- 執行器:定時Job實際執行的服務器地址。
- 任務管理:執行服務器配置定時任務規則、路由策略、允許模式等。
任務Hanlder究竟該如何編寫:
- 繼承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”;
- 注冊到Spring容器中:添加"@Component"注解,被Spring容器掃描為Bean實例。
- 注冊到執行器工廠:添加"@JobHandler(value=“自定義jobhandler名稱”)“注解;value對應的值是調度中心新建任務的JobHandler屬性的值
說明:
(1) 其實這里面使用”@Jobhandler"注解是方便將value值與任務執行類對應好,以便在進行任務調度的時候可以找到對應的任務執行類,然后執行方法;
(2) 繼承"IJobHandler",然后實現execute方法,這里面利用反射的思想,只要是繼承了IJobHandler這個類,就自動執行execute方法。
高可用設計
所謂高可用設計,指的是執行器服務器和調度中心服務器。前者利用分布式調度中心便可以解決同一套代碼在不同的執行器服務器中執行不會出現任務重復消息的問題;但是咱們也需要考慮調度中心服務器是否高可用,如下圖:
所以此時需要利用Nginx的負載均衡的特性,保證調度平台高可用,相關設計如下:
快速入門
源碼下載:http://gitee.com/xuxueli0323/xxl-job
初始化調度數據庫
下載項目源碼並解壓,獲取 “調度數據庫初始化SQL腳本” 並執行即可。
調度數據庫初始化SQL腳本:/xxl-job/doc/db/tables_xxl_job.sql
調度中心支持集群部署,集群情況下各節點務必連接同一個mysql實例;
如果mysql做主從,調度中心集群節點務必強制走主庫;
編譯源碼
解壓源碼,按照maven格式將源碼導入IDE, 使用maven進行編譯即可,源碼結構如下:
xxl-job-admin:調度中心
xxl-job-core:公共依賴
xxl-job-executor-samples:執行器Sample示例(選擇合適的版本執行器,可直接使用,也可以參考其並將現有項目改造成執行器)
:xxl-job-executor-sample-springboot:Springboot版本,通過Springboot管理執行器,推薦這種方式;
:xxl-job-executor-sample-frameless:無框架版本;
配置部署調度中心
調度中心項目:xxl-job-admin
作用:統一管理任務調度平台上調度任務,負責觸發調度執行,並且提供任務管理平台。
調度中心配置
調度中心配置文件地址:/xxl-job/xxl-job-admin/src/main/resources/application.properties
調度中心配置內容說明:
### 調度中心JDBC鏈接:鏈接地址請保持和 2.1章節 所創建的調度數據庫的地址一致 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=root_pwd spring.datasource.driver-class-name=com.mysql.jdbc.Driver ### 報警郵箱 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 ### 調度中心通訊TOKEN [選填]:非空時啟用; xxl.job.accessToken= ### 調度中心國際化配置 [必填]: 默認為 "zh_CN"/中文簡體, 可選范圍為 "zh_CN"/中文簡體, "zh_TC"/中文繁體 and "en"/英文; xxl.job.i18n=zh_CN ## 調度線程池最大線程配置【必填】 xxl.job.triggerpool.fast.max=200 xxl.job.triggerpool.slow.max=100 ### 調度中心日志表數據保存天數 [必填]:過期日志自動清理;限制大於等於7時生效,否則, 如-1,關閉自動清理功能; xxl.job.logretentiondays=30
部署項目
如果已經正確進行上述配置,可將項目編譯打包部署。
調度中心訪問地址:http://localhost:8080/xxl-job-admin (該地址執行器將會使用到,作為回調地址)
默認登錄賬號 “admin/123456”, 登錄后運行界面如下圖所示。
調度中心集群
調度中心支持集群部署,提升調度系統容災和可用性。
調度中心集群部署時,幾點要求和建議:
- DB配置保持一致;
- 集群機器時鍾保持一致(單機集群忽視);
- 建議:推薦通過nginx為調度中心集群做負載均衡,分配域名。調度中心訪問、執行器回調配置、調用API服務等操作均通過該域名進行。
配置部署執行器
執行器項目:xxl-job-executor-sample-springboot (提供多種版本執行器供選擇,現以 springboot 版本為例,可直接使用,也可以參考其並將現有項目改造成執行器)
作用:負責接收“調度中心”的調度並執行;可直接部署執行器,也可以將執行器集成到現有業務項目中。
1、maven依賴
確認pom文件中引入了 “xxl-job-core” 的maven依賴;
2、執行器配置
執行器配置,配置文件地址:/xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties
執行器配置,配置內容說明:
### 調度中心部署跟地址 [選填]:如調度中心集群部署存在多個地址則用逗號分隔。執行器將會使用該地址進行"執行器心跳注冊"和"任務結果回調";為空則關閉自動注冊; xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin ### 執行器通訊TOKEN [選填]:非空時啟用; xxl.job.accessToken= ### 執行器AppName [選填]:執行器心跳注冊分組依據;為空則關閉自動注冊 xxl.job.executor.appname=xxl-job-executor-sample ### 執行器注冊 [選填]:優先使用該配置作為注冊地址,為空時使用內嵌服務 ”IP:PORT“ 作為注冊地址。從而更靈活的支持容器類型執行器動態IP和動態映射端口問題。 xxl.job.executor.address= ### 執行器IP [選填]:默認為空表示自動獲取IP,多網卡時可手動設置指定IP,該IP不會綁定Host僅作為通訊實用;地址信息用於 "執行器注冊" 和 "調度中心請求並觸發任務"; xxl.job.executor.ip= ### 執行器端口號 [選填]:小於等於0則自動獲取;默認端口為9999,單機部署多個執行器時,注意要配置不同執行器端口; xxl.job.executor.port=9999 ### 執行器運行日志文件存儲磁盤路徑 [選填] :需要對該路徑擁有讀寫權限;為空則使用默認路徑; xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler ### 執行器日志文件保存天數 [選填] : 過期日志自動清理, 限制值大於等於3時生效; 否則, 如-1, 關閉自動清理功能; xxl.job.executor.logretentiondays=30
3、執行器組件配置
執行器組件,配置文件地址:/xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java
執行器組件,配置內容說明:
@Bean public XxlJobSpringExecutor xxlJobExecutor() { logger.info(">>>>>>>>>>> xxl-job config init."); XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); xxlJobSpringExecutor.setAdminAddresses(adminAddresses); xxlJobSpringExecutor.setAppname(appname); xxlJobSpringExecutor.setIp(ip); xxlJobSpringExecutor.setPort(port); xxlJobSpringExecutor.setAccessToken(accessToken); xxlJobSpringExecutor.setLogPath(logPath); xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); return xxlJobSpringExecutor; }
4、部署執行器項目
如果已經正確進行上述配置,可將執行器項目編譯打部署,系統提供多種執行器Sample示例項目,選擇其中一個即可,各自的部署方式如下。
xxl-job-executor-sample-springboot:項目編譯打包成springboot類型的可執行JAR包,命令啟動即可;
xxl-job-executor-sample-frameless:項目編譯打包成JAR包,命令啟動即可;
至此“執行器”項目已經部署結束。
5、執行器集群
執行器支持集群部署,提升調度系統可用性,同時提升任務處理能力。
執行器集群部署時,幾點要求和建議:
- 執行器回調地址(xxl.job.admin.addresses)需要保持一致;執行器根據該配置進行執行器自動注冊等操作。
- 同一個執行器集群內AppName(xxl.job.executor.appname)需要保持一致;調度中心根據該配置動態發現不同集群的在線執行器列表。
任務配置
前提:請確認“調度中心”和“執行器”項目已經成功部署並啟動;
1、路由策略
當執行器集群部署時,提供豐富的路由策略,包括;
- FIRST(第一個):固定選擇第一個機器;
- LAST(最后一個):固定選擇最后一個機器;
- ROUND(輪詢):;
- RANDOM(隨機):隨機選擇在線的機器;
- CONSISTENT_HASH(一致性HASH):每個任務按照Hash算法固定選擇某一台機器,且所有任務均勻散列在不同機器上。
- LEAST_FREQUENTLY_USED(最不經常使用):使用頻率最低的機器優先被選舉;
- LEAST_RECENTLY_USED(最近最久未使用):最久未使用的機器優先被選舉;
- FAILOVER(故障轉移):按照順序依次進行心跳檢測,第一個心跳檢測成功的機器選定為目標執行器並發起調度;
- BUSYOVER(忙碌轉移):按照順序依次進行空閑檢測,第一個空閑檢測成功的機器選定為目標執行器並發起調度;
- SHARDING_BROADCAST(分片廣播):廣播觸發對應集群中所有機器執行一次任務,同時系統自動傳遞分片參數;可根據分片參數開發分片任務;
2、子任務
每個任務都擁有一個唯一的任務ID(任務ID可以從任務列表獲取),當本任務執行結束並且執行成功時,將會觸發子任務ID所對應的任務的一次主動調度。
3、調度過期策略
- 忽略:調度過期后,忽略過期的任務,從當前時間開始重新計算下次觸發時間;
- 立即執行一次:調度過期后,立即執行一次,並從當前時間開始重新計算下次觸發時間;
4、阻塞處理策略
調度過於密集執行器來不及處理時的處理策略;
- 單機串行(默認):調度請求進入單機執行器后,調度請求進入FIFO隊列並以串行方式運行;
- 丟棄后續調度:調度請求進入單機執行器后,發現執行器存在運行的調度任務,本次請求將會被丟棄並標記為失敗;
- 覆蓋之前調度:調度請求進入單機執行器后,發現執行器存在運行的調度任務,將會終止運行中的調度任務並清空隊列,然后運行本地調度任務;
5、任務超時時間
支持自定義任務超時時間,任務運行超時將會主動中斷任務;
6、失敗重試次數
支持自定義任務失敗重試次數,當任務失敗時將會按照預設的失敗重試次數主動進行重試;