您好,登錄后才能下訂單哦!
無(wú)論是互聯(lián)網(wǎng)應(yīng)用或者企業(yè)級(jí)應(yīng)用,都充斥著大量的批處理任務(wù)。我們常常需要一些任務(wù)調(diào)度系統(tǒng)來(lái)幫助解決問(wèn)題。隨著微服務(wù)化架構(gòu)的逐步演進(jìn),單體架構(gòu)逐漸演變?yōu)榉植际?、微服?wù)架構(gòu)。在此背景下,很多原先的任務(wù)調(diào)度平臺(tái)已經(jīng)不能滿足業(yè)務(wù)系統(tǒng)的需求,于是出現(xiàn)了一些基于分布式的任務(wù)調(diào)度平臺(tái)。
在實(shí)際業(yè)務(wù)開(kāi)發(fā)過(guò)程中,很多時(shí)候我們無(wú)可避免地需要使用一些定時(shí)任務(wù)來(lái)解決問(wèn)題。通常我們會(huì)有多種解決方案:使用 Crontab 或 SpringCron (當(dāng)然這種情況可能機(jī)器很少而且任務(wù)簡(jiǎn)單又不是很多的情況下)。然而,當(dāng)應(yīng)用復(fù)雜度升高、定時(shí)任務(wù)數(shù)量增多且任務(wù)之間產(chǎn)生依賴關(guān)系時(shí),Crontab 進(jìn)行定時(shí)任務(wù)的管理配置就會(huì)非?;靵y,嚴(yán)重影響工作效率。這時(shí)就會(huì)產(chǎn)生一系列問(wèn)題:
隨著互聯(lián)網(wǎng)的發(fā)展,分布式服務(wù)架構(gòu)勢(shì)越來(lái)越流行。相應(yīng)的也需要一個(gè)分布式任務(wù)調(diào)度系統(tǒng)來(lái)管理分布式架構(gòu)中的定時(shí)任務(wù)。
當(dāng)垂直應(yīng)用越來(lái)越多,應(yīng)用之間交互也會(huì)越來(lái)越復(fù)雜,通常我們采用分布式或者微服務(wù)架構(gòu),將核心業(yè)務(wù)抽取出來(lái),形成單獨(dú)的服務(wù)。一個(gè)獨(dú)立的微服務(wù)群體逐漸形成穩(wěn)定的服務(wù)中心,使得業(yè)務(wù)應(yīng)用能更快地響應(yīng)多變的市場(chǎng)需求。
此時(shí),用于提高業(yè)務(wù)復(fù)用及整合的分布式服務(wù)框架成為關(guān)鍵。同時(shí),由于服務(wù)獨(dú)立,一般能做到定時(shí)任務(wù)獨(dú)立的情況,任務(wù)的更改對(duì)于整體系統(tǒng)的影響小之又小。通常我們會(huì)采用任務(wù)與調(diào)度分離的方式(如上圖所示),任務(wù)的執(zhí)行邏輯無(wú)需關(guān)注調(diào)度與編排,同時(shí)可以保證執(zhí)行器和調(diào)度的高可用,易于開(kāi)發(fā)和維護(hù)。
在分布式服務(wù)架構(gòu)的基礎(chǔ)上,由于獨(dú)立業(yè)務(wù)的數(shù)量可能很多,此時(shí)如果定時(shí)任務(wù)單獨(dú)在該服務(wù)中實(shí)現(xiàn),很可能會(huì)出現(xiàn)難以管理的情況,且避免不了由于定時(shí)任務(wù)的更改而導(dǎo)致的業(yè)務(wù)重啟。因此,一個(gè)獨(dú)立的分布式任務(wù)調(diào)度系統(tǒng)是很必要的,可以用來(lái)全局統(tǒng)籌管理所有的定時(shí)任務(wù)。同時(shí),將任務(wù)的配置單獨(dú)抽離出來(lái),作為該分布式任務(wù)調(diào)度系統(tǒng)的功能,就能做到定時(shí)任務(wù)的更改不影響任何業(yè)務(wù),也不影響整個(gè)系統(tǒng):
SIA是宜信公司基礎(chǔ)開(kāi)發(fā)平臺(tái)Simple is Awesome的簡(jiǎn)稱,SIA-TASK(微服務(wù)任務(wù)調(diào)度平臺(tái))是其中的一項(xiàng)重要產(chǎn)品,SIA-TASK契合當(dāng)前微服務(wù)架構(gòu)模式,具有跨平臺(tái)、可編排、高可用、無(wú)侵入、一致性、異步并行、動(dòng)態(tài)擴(kuò)展、實(shí)時(shí)監(jiān)控等特點(diǎn)。
開(kāi)源地址:https://github.com/siaorg/sia-task
我們先對(duì)比市場(chǎng)上主流的開(kāi)源分布式任務(wù)調(diào)度框架,分析其優(yōu)缺點(diǎn),然后再介紹我們的技術(shù)選型。
下面我們簡(jiǎn)單對(duì)比下 SIA-TASK 與這些任務(wù)調(diào)度框架:
任務(wù)編排 | 任務(wù)分片 | 跨平臺(tái) | 高可用 | 故障轉(zhuǎn)移 | 實(shí)時(shí)監(jiān)控 | |
---|---|---|---|---|---|---|
SIA-TASK | √ | √ | √ | √ | √ | √ |
Quartz | × | × | .NET | √ | × | API監(jiān)控 |
TBSchedule | × | √ | × | √ | √ | √ |
Elastic-Job | × | √ | × | √ | √ | √ |
Saturn | × | √ | √ | √ | √ | √ |
Antares | √ | √ | × | √ | √ | √ |
Uncode-Schedule | × | × | × | √ | √ | √ |
XXL-JOB | 子任務(wù)依賴 | √ | × | √ | √ | √ |
可以發(fā)現(xiàn),這些調(diào)度框架基本上都支持高可用、故障轉(zhuǎn)移與實(shí)時(shí)監(jiān)控等功能,但是對(duì)于任務(wù)編排、任務(wù)分片與跨平臺(tái)等功能的支持各有側(cè)重點(diǎn)。SIA-TASK 將全面支持這些功能。
SIA-TASK借鑒微服務(wù)設(shè)計(jì)思想,獲取分布在每個(gè)執(zhí)行器節(jié)點(diǎn)上的任務(wù)(Task)元數(shù)據(jù),進(jìn)行匯報(bào),上傳注冊(cè)中心。利用在線可編輯方式支持任務(wù)在線編排、動(dòng)態(tài)修改任務(wù)時(shí)鐘;使用 Http 協(xié)議作為交互傳輸協(xié)議。數(shù)據(jù)交互格式統(tǒng)一使用Json。用戶通過(guò)編排器(下文會(huì)做介紹)進(jìn)行操作,觸發(fā)事件,調(diào)度器接收事件,由調(diào)度中心進(jìn)行時(shí)鐘解析,執(zhí)行任務(wù)流程,進(jìn)行任務(wù)通知。
SIA-TASK 采用任務(wù)和調(diào)度分離的方式,業(yè)務(wù)的執(zhí)行任務(wù)邏輯和調(diào)度邏輯完全分離。系統(tǒng)組成共涉及以下幾個(gè)核心概念:
SIA-TASK 可以分為三大模塊(調(diào)度中心、編排中心和執(zhí)行器)、兩大組件(持久化存儲(chǔ)和注冊(cè)中心)。這三大模塊和兩大組件的作用如下:
SIA-TASK 使用 SpringBoot 體系作為架構(gòu)選型,基于Quartz及Zookeeper進(jìn)行二次開(kāi)發(fā),支持相應(yīng)的特×××,SIA-TASK 的邏輯架構(gòu)圖如下圖所示:
任務(wù)調(diào)度中心負(fù)責(zé)任務(wù)調(diào)度,管理調(diào)度信息,按照調(diào)度配置發(fā)出調(diào)度請(qǐng)求,自身不承擔(dān)業(yè)務(wù)代碼。調(diào)度系統(tǒng)與任務(wù)解耦,提高了系統(tǒng)可用性和穩(wěn)定性,同時(shí)調(diào)度系統(tǒng)性能不再受限于任務(wù)模塊;支持可視化、簡(jiǎn)單且動(dòng)態(tài)地管理調(diào)度信息,包括任務(wù)新建,更新,刪除和任務(wù)報(bào)警等,所有上述操作都會(huì)實(shí)時(shí)生效,同時(shí)支持監(jiān)控調(diào)度結(jié)果以及執(zhí)行日志,支持執(zhí)行器故障恢復(fù)。
任務(wù)編排中心是分布式調(diào)度中心支持在線任務(wù)模型編排的組件;依托于UI可進(jìn)行web端任務(wù)編排。
我們可以通過(guò)上述基礎(chǔ)模型來(lái)編排一些復(fù)雜的調(diào)度模型,例如:
SIA-TASK的UI編排界面:
編排結(jié)束后查看task的編排信息如下圖所示:
同時(shí),編排中心還提供首頁(yè)統(tǒng)計(jì)數(shù)據(jù)查看、調(diào)度監(jiān)控、Job管理、Task管理以及日志管理功能。
負(fù)責(zé)接收調(diào)度請(qǐng)求并執(zhí)行任務(wù)邏輯。任務(wù)模塊專注于任務(wù)的執(zhí)行等操作,開(kāi)發(fā)和維護(hù)更加簡(jiǎn)單和高效;
執(zhí)行器支持兩種類型:
(1) 如果使用 sia-task-hunter,支持SpringBoot項(xiàng)目和Spring項(xiàng)目, 引入 sia-task-hunter,任務(wù)(Task)抓取客戶端。合規(guī)的HTTP接口(稱之為T(mén)ask)任務(wù)會(huì)自動(dòng)被抓取并上傳注冊(cè)中心;
(2) 如果不使用 sia-task-hunter,只需提供任務(wù)可調(diào)用的HTTP接口,此時(shí)需要業(yè)務(wù)手動(dòng)錄入,且自行控制該任務(wù)的并發(fā)調(diào)用控制。
分布式框架采用Zookeeper作為注冊(cè)中心。
(1) 任務(wù)注冊(cè)
調(diào)度中心和執(zhí)行集群都以Zookeeper作為注冊(cè)中心,所有數(shù)據(jù)以節(jié)點(diǎn)及節(jié)點(diǎn)內(nèi)容的形式注冊(cè),通過(guò)定時(shí)匯報(bào)主機(jī)狀態(tài)保持存活在Zookeeper上。
(2) 元數(shù)據(jù)存儲(chǔ)
注冊(cè)中心不僅僅提供注冊(cè)服務(wù),并且存儲(chǔ)每個(gè)執(zhí)行器的信息(包括執(zhí)行器實(shí)例信息,執(zhí)行器上傳的Task元數(shù)據(jù),以及任務(wù)運(yùn)行時(shí)的一些臨時(shí)狀態(tài)數(shù)據(jù))。
(3) 事件發(fā)布
基于Zookeeper事件推送機(jī)制,進(jìn)行任務(wù)的發(fā)布,通過(guò)平衡算法保證調(diào)度器任務(wù)搶占的分布均衡。
(4) 負(fù)載均衡
保證調(diào)度器獲取執(zhí)行Job的個(gè)數(shù)均衡,避免單一節(jié)點(diǎn)壓力。
這里采用MySQL作為數(shù)據(jù)持久化解決方案。
除了Task動(dòng)態(tài)元數(shù)據(jù)保存在注冊(cè)中心之外,其他相關(guān)的元數(shù)據(jù)都存入MySQL,包括但不限于:手動(dòng)錄入的Task、配置的Job信息、編排的Task依賴信息、調(diào)度日志、業(yè)務(wù)人員操作日志、Task執(zhí)行日志等。
(1) 用戶可以通過(guò)UI進(jìn)行Job創(chuàng)建??梢赃x擇Job類型,設(shè)置預(yù)警郵箱,設(shè)置Job描述。然后為創(chuàng)建的Job進(jìn)行任務(wù)Task編排。
(2) Job創(chuàng)建完畢并且設(shè)置Task編排關(guān)系后可進(jìn)行任務(wù)發(fā)布,通過(guò)UI對(duì)相應(yīng)的Job進(jìn)行操作(激活,執(zhí)行一次,停止以及刪除操作)。
(3) 用戶的Task任務(wù)可以是通過(guò)抓取器抓取的,亦可以使用UI手動(dòng)創(chuàng)建。
(1) Job創(chuàng)建完成之后,可以選擇激活觸發(fā)定時(shí)任務(wù);
(2) Job到達(dá)預(yù)訂時(shí)間后,調(diào)度中心觸發(fā)Job,然后按照預(yù)定的Task編排邏輯通過(guò)http通知Task執(zhí)行器進(jìn)行執(zhí)行,并異步監(jiān)聽(tīng)任務(wù)執(zhí)行結(jié)果;
(3) 若執(zhí)行結(jié)果成功,則判斷是否存在后置Task,若存在,則繼續(xù)下一次調(diào)度,若不存在,則說(shuō)明該Job執(zhí)行完畢,結(jié)束本次調(diào)用;若執(zhí)行結(jié)果失敗,則觸發(fā)故障恢復(fù)策略:立即停止、忽略本次失敗、多次嘗試、轉(zhuǎn)到其它執(zhí)行器執(zhí)行。
Job在整個(gè)生命周期內(nèi)存在四種狀態(tài),分別是:已停止(NULL)、準(zhǔn)備中(READY)、開(kāi)始運(yùn)行(RUNNING)、異常停止(STOP),狀態(tài)流轉(zhuǎn)及流轉(zhuǎn)條件如下圖所示。
SIA-TASK 的物理網(wǎng)絡(luò)拓?fù)鋱D如下所示:
SIA-TASK 的模塊間交互設(shè)計(jì)思路:
(1) 通過(guò)編排中心創(chuàng)建Task任務(wù)或通過(guò)Hunter自動(dòng)抓取,并將 Task 信息異步保存到DB;創(chuàng)建Job并激活,在zookeeper中創(chuàng)建JobKey。
(2) 調(diào)度中心會(huì)監(jiān)聽(tīng)zookeeper中JobKey創(chuàng)建事件,然后搶占創(chuàng)建的Job,搶占成功后加入quartz定時(shí)任務(wù),當(dāng)時(shí)間到達(dá)即觸發(fā)Job運(yùn)行。調(diào)度中心異步調(diào)用執(zhí)行器服務(wù)執(zhí)行Job中的 Task (可能存在多個(gè) Task ,遵循 Task 失敗策略),并將結(jié)果返回到調(diào)度中心。
(3) 將Job執(zhí)行狀態(tài)隨時(shí)在zookeeper上更改,通過(guò)編排中心的查詢接口可以進(jìn)行查詢。
(4) Job執(zhí)行結(jié)束后,等待下一次執(zhí)行。
編排中心可以與DB和zookeeper進(jìn)行數(shù)據(jù)交互,其主要功能可分為三方面:
編排中心首頁(yè)監(jiān)控展示如下:
調(diào)度中心主要與DB、ZK和執(zhí)行器進(jìn)行交互,其主要功能可分為以下幾個(gè)方面:
執(zhí)行器可以與ZK和調(diào)度中心進(jìn)行交互,其主要功能可分為兩個(gè)方面:
執(zhí)行器 Task示例:
@OnlineTask(description = "在線任務(wù)示例",enableSerial=true)
@RequestMapping(value = "/example", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
@CrossOrigin(methods = { RequestMethod.POST }, origins = "*")
@ResponseBody
public String example(@RequestBody String json) {
/**
* TODO:客戶端業(yè)務(wù)邏輯處理
*/
Map<String, String> info = new HashMap<String, String>();
info.put("status", "success");
info.put("result", "as you need");
return JSONHelper.toString(info);
}
由此可見(jiàn),任務(wù) Task 編寫(xiě)非常簡(jiǎn)單。
分布式服務(wù)一般都要考慮高可用方案,同樣 SIA-TASK 為了保證高可用,針對(duì)不同的服務(wù)組件進(jìn)行了不同維度增強(qiáng)。
SIA-TASK 通過(guò)前后端分離、服務(wù)拆分等措施實(shí)現(xiàn)了編排中心的高可用。當(dāng)集群中某實(shí)例失效后,不會(huì)影響集群的其它實(shí)例,因此無(wú)需特殊操作即可使用集群中其它的可用編排中心。
如果調(diào)度中心集群中的某個(gè)實(shí)例節(jié)點(diǎn)服務(wù)宕機(jī)后,這個(gè)實(shí)例節(jié)點(diǎn)上的所有Job會(huì)平滑遷移到集群中可用的實(shí)例上,不會(huì)造成定時(shí)任務(wù)的執(zhí)行缺失,同時(shí),當(dāng)崩潰后的實(shí)例修復(fù)成功重新接入該集群時(shí),會(huì)繼續(xù)搶占Job提供服務(wù)。
調(diào)度采用線程池方式實(shí)現(xiàn),避免單線程因阻塞而引起任務(wù)調(diào)度延遲。程池里的線程數(shù),默認(rèn)值是10,當(dāng)執(zhí)行任務(wù)會(huì)并發(fā)執(zhí)行多個(gè)耗時(shí)任務(wù)時(shí),要根據(jù)業(yè)務(wù)特點(diǎn)選擇線程池的大小。
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 60
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
SIA-TASK 根據(jù)quartz自身提供的threadPool再次進(jìn)行線程池的利用。進(jìn)行線程池重新定義,針對(duì)每個(gè)Job去分配一個(gè)獨(dú)有的線程池。線程池的大小可根據(jù)Job自身編排的 Task 個(gè)數(shù)的大小進(jìn)行動(dòng)態(tài)伸縮,從而保證每個(gè)Job的調(diào)度線程完全獨(dú)立,不在會(huì)因?yàn)榫幣?Task 個(gè)數(shù)的陡增而耗盡線程資源。同時(shí)提供線程池資源的回收邏輯,在Job進(jìn)行永久性終止時(shí)回收為期分配的線程池資源。
public static ExecutorService getExecutorService(String JobKey) {
ExecutorService exec = executorPool.get(JobKey);
if (exec == null) {
LOGGER.info(Constants.LOG_PREFIX + "Initialize thread pool for running Jobs,Job is {}",JobKey);
exec = Executors.newCachedThreadPool();
executorPool.putIfAbsent(JobKey, exec);
exec = executorPool.get(JobKey);
}
return exec;
}
SIA-TASK 針對(duì)Job的整個(gè)調(diào)度生命周期進(jìn)行全面跟蹤,利用AOP進(jìn)行日志增強(qiáng),調(diào)度中心每觸發(fā)一次Job調(diào)度就會(huì)進(jìn)行日志記錄。同時(shí)針對(duì)Job編排的 Task 執(zhí)行也會(huì)進(jìn)行記錄任務(wù)日志。
日志分為Job日志和 Task 日志:
public interface RestTemplate {
/**
* 異步Post方法 * @param request
* @param responseType
* @param uriVariables
* @param <T>
* @return
*/
<T> ListenableFuture<ResponseEntity<T>> postAsyncForEntity(Request request, Class<T> responseType, Object... uriVariables); }
SIA-TASK 從物理資源角度設(shè)計(jì)了調(diào)度資源池,出于一些特殊情況的考量我們針對(duì)調(diào)度器進(jìn)行了池化;調(diào)度器可以通過(guò)不同的操作進(jìn)行狀態(tài)的轉(zhuǎn)變,從而進(jìn)行能力的轉(zhuǎn)化。
考慮網(wǎng)絡(luò)的不穩(wěn)定性,SIA-TASK 針對(duì)網(wǎng)絡(luò)的不穩(wěn)定性也做出了非常重要的設(shè)計(jì),對(duì)于節(jié)點(diǎn)的連通性的測(cè)試支持以及針對(duì) Task 運(yùn)行實(shí)例節(jié)點(diǎn)健康的預(yù)感知,保證提前感知 Task 實(shí)例節(jié)點(diǎn)的健康情況,保證調(diào)度 Task 高可用。
同時(shí)也保證了執(zhí)行器實(shí)例針對(duì)網(wǎng)絡(luò)導(dǎo)致鏈接中斷的問(wèn)題,SIA-TASK 重新設(shè)計(jì)了zookeeper的重連機(jī)制,保證 Task 運(yùn)行實(shí)例節(jié)點(diǎn)因網(wǎng)絡(luò)問(wèn)題丟失鏈接后還能進(jìn)行恢復(fù)重試,直到恢復(fù)正常后并入執(zhí)行池中正常接收任務(wù)的調(diào)度。
至此對(duì)微服務(wù)任務(wù)調(diào)度平臺(tái) SIA-TASK 做了一個(gè)簡(jiǎn)要的介紹,包括設(shè)計(jì)背景、架構(gòu)設(shè)計(jì)以及產(chǎn)品組件功能與特性。微服務(wù)任務(wù)調(diào)度平臺(tái) SIA-TASK 基本上解決了當(dāng)前的業(yè)務(wù)需求,提供簡(jiǎn)單高效的編排調(diào)度服務(wù)。SIA-TASK 會(huì)持續(xù)迭代,提供更為完善的服務(wù)。之后也會(huì)提供相關(guān)技術(shù)文檔和使用文檔。
鏈接指南
開(kāi)源地址:https://github.com/siaorg/sia-task
拓展閱讀:宜信開(kāi)源微服務(wù)任務(wù)調(diào)度平臺(tái)(SIA-TASK)
作者:毛正衛(wèi)/×××飛/梁鑫
原文首發(fā):SpringCloud社區(qū)
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。