分布式任務(wù)調(diào)度系統(tǒng)設(shè)計(jì)

一、思路

任務(wù)調(diào)度器、任務(wù)執(zhí)行器、任務(wù)

任務(wù)調(diào)度器不關(guān)心業(yè)務(wù)邏輯,只關(guān)心任務(wù)的觸發(fā)策略、失敗策略、路由策略、阻塞處理策略

任務(wù)執(zhí)行器只需要監(jiān)聽任務(wù)觸發(fā)接口,按要求執(zhí)行任務(wù),成功或失敗時(shí)異步通知任務(wù)調(diào)度器

任務(wù)的基本屬性需要包含任務(wù)ID、觸發(fā)策略、失敗策略、路由策略、阻塞處理策略、創(chuàng)建時(shí)間、創(chuàng)建用戶、任務(wù)參數(shù)、任務(wù)當(dāng)前搶占調(diào)度器、任務(wù)狀態(tài)(調(diào)度中、執(zhí)行中、執(zhí)行完成)

HA集群

為了避免單點(diǎn)故障,任務(wù)調(diào)度系統(tǒng)通常需要通過集群實(shí)現(xiàn)系統(tǒng)高可用,同時(shí)通過擴(kuò)展提高系統(tǒng)的任務(wù)負(fù)載量上限。

鑒于任務(wù)調(diào)度系統(tǒng)的特殊性,“調(diào)度”和“執(zhí)行”兩個(gè)模塊需要均支持集群部署,由于職責(zé)不同,因此各自集群側(cè)重點(diǎn)也有有所不同。

  • “調(diào)度器”集群,目標(biāo)為避免調(diào)度模塊單點(diǎn)故障。同時(shí),集群節(jié)點(diǎn)需要通過鎖或命名服務(wù)保證單個(gè)任務(wù)的單次觸發(fā),只在其中一個(gè)節(jié)點(diǎn)上生效,以防止任務(wù)的重復(fù)觸發(fā)。
    • 調(diào)度器為何采用集群而不是主從?
      • 主從模式只能提供HA的特性,不能提高提高系統(tǒng)的任務(wù)負(fù)載量上限。
      • 主從需要實(shí)現(xiàn)選舉算法,保證CP或者AP
      • 集群只需要將狀態(tài)都遷移到全局的存儲(chǔ)器中(例如DB),任務(wù)可以采用搶占機(jī)制(全局鎖),搶占后在任務(wù)后標(biāo)識(shí)任務(wù)狀態(tài)即可。
  • “執(zhí)行器”集群:目標(biāo)為避免任務(wù)模塊單點(diǎn)故障。進(jìn)一步可以通過自定義路由策略實(shí)現(xiàn)Failover等高級(jí)功能,從而在執(zhí)行器某臺(tái)機(jī)器節(jié)點(diǎn)故障時(shí)自動(dòng)轉(zhuǎn)移不會(huì)影響到任務(wù)的正常觸發(fā)執(zhí)行。

節(jié)點(diǎn)故障處理

節(jié)點(diǎn):
任務(wù)調(diào)度器S1、S2、S3
任務(wù)執(zhí)行器E1、E2、E3
任務(wù)T1、T2、T3

情景1:

在S1上手動(dòng)觸發(fā)一個(gè)任務(wù)T1,T1任務(wù)信息入庫(任務(wù)狀態(tài)調(diào)度中),根據(jù)路由策略選擇E3執(zhí)行任務(wù)T1【a】(返回畫面任務(wù)手動(dòng)觸發(fā)成功,任務(wù)狀態(tài)執(zhí)行中),任務(wù)T1進(jìn)入E3的任務(wù)隊(duì)列【b】,E3開始執(zhí)行任務(wù)【c】,任務(wù)執(zhí)行完成【d】,結(jié)果同步通知S2【e】(返回通知成功后才可以提交任務(wù)的事務(wù)),S2根據(jù)任務(wù)信息修改數(shù)據(jù)庫T1任務(wù)信息記錄【f】(任務(wù)狀態(tài)執(zhí)行完畢,畫面定時(shí)刷新查詢?nèi)蝿?wù)狀態(tài))

假設(shè)在【a】處時(shí),T1發(fā)生宕機(jī),需要保證T1的任務(wù)信息不會(huì)入庫,開啟DB事務(wù),保證任務(wù)成功調(diào)度給執(zhí)行器后再提交事務(wù);畫面會(huì)顯示錯(cuò)誤通知,提示調(diào)度器宕機(jī),需要重新刷新畫面,Nginx將自動(dòng)選擇新的S2或S3節(jié)點(diǎn)繼續(xù)提供服務(wù)

假設(shè)在【b、c、d、e】處時(shí),E3發(fā)生宕機(jī),此時(shí)調(diào)度器S1、S2、S3發(fā)現(xiàn)E3下線(執(zhí)行器下線Hook檢查),在DB中查詢分配給E3的任務(wù)(執(zhí)行中的任務(wù)),重新?lián)屨荚撊蝿?wù),假設(shè)S2搶占到該任務(wù),根據(jù)任務(wù)T1的策略調(diào)度任務(wù),選擇E1執(zhí)行任務(wù)T1,T1任務(wù)執(zhí)行完畢任務(wù)后異步隨機(jī)通知調(diào)度器S1,S1根據(jù)任務(wù)信息修改數(shù)據(jù)庫T1任務(wù)信息記錄

假設(shè)在【e】處時(shí),S2發(fā)生宕機(jī),E3發(fā)現(xiàn)通知失敗,將會(huì)隨機(jī)重新選擇可用的調(diào)度器節(jié)點(diǎn)再次發(fā)起通知,如果超過重試次數(shù)仍然無法通知成功(說明E3與調(diào)度器間出現(xiàn)了網(wǎng)絡(luò)問題,調(diào)度器會(huì)認(rèn)為E3下線),則發(fā)生異常,保證任務(wù)的事務(wù)回滾,主動(dòng)通知調(diào)度器集群執(zhí)行器E3故障下線,調(diào)度器集群將調(diào)度器列表中的E3排除,E3故障排除后重啟E3即可重新注冊到調(diào)度器中

假設(shè)在【f】處時(shí),S2發(fā)生宕機(jī),E3發(fā)現(xiàn)通知的連接異常斷開,將會(huì)隨機(jī)重新選擇可用的調(diào)度器節(jié)點(diǎn)再次發(fā)起通知,如果超過重試次數(shù)仍然無法通知成功(說明E3與調(diào)度器間出現(xiàn)了網(wǎng)絡(luò)問題,調(diào)度器會(huì)認(rèn)為E3下線),則發(fā)生異常,保證任務(wù)的事務(wù)回滾,主動(dòng)通知調(diào)度器集群執(zhí)行器E3故障下線,調(diào)度器集群將調(diào)度器列表中的E3排除,E3故障排除后重啟E3即可重新注冊到調(diào)度器中

假設(shè)在【f】處時(shí),E3發(fā)生宕機(jī),S2發(fā)現(xiàn)響應(yīng)發(fā)生異常,此時(shí)需要將事務(wù)回滾,既不能將任務(wù)狀態(tài)修改為執(zhí)行完畢,然后E3宕機(jī)無法向集群中心發(fā)送心跳,觸發(fā)調(diào)度器的下線檢查,任務(wù)將會(huì)重新被調(diào)度器搶占調(diào)度執(zhí)行。

觸發(fā)策略

任務(wù)的觸發(fā)方式可以分為定時(shí)觸發(fā)和手動(dòng)觸發(fā),定時(shí)觸發(fā)可以是cron表達(dá)式形式,也可以是自定義觸發(fā)策略類形式。

觸發(fā)策略可以是delay、FixedDelay、FixedRate、cron表達(dá)式、手動(dòng)觸發(fā)、以及自定義觸發(fā)實(shí)現(xiàn)

失敗策略

這里的失敗策略指的是業(yè)務(wù)發(fā)生失敗的處理策略,而不是因?yàn)楣?jié)點(diǎn)故障導(dǎo)致任務(wù)沒有執(zhí)行完成導(dǎo)致的失敗

任務(wù)失敗是一種很常見的情況,當(dāng)任務(wù)失敗時(shí)有兩點(diǎn)非常重要,一個(gè)是快速發(fā)現(xiàn)問題,另一個(gè)是及時(shí)解決問題。

任務(wù)業(yè)務(wù)邏輯千差萬別,如索引同步、pv統(tǒng)計(jì)、訂單超時(shí)處理等等。任務(wù)失敗可能會(huì)導(dǎo)致非常嚴(yán)重的后果,比如索引同步任務(wù)失敗可能導(dǎo)致搜索不匹配,pv統(tǒng)計(jì)失敗可能導(dǎo)致打點(diǎn)報(bào)表的生成,訂單超時(shí)處理任務(wù)的失敗可能導(dǎo)致商品庫存的大量無效占用等等。

針對上述情況,通常有幾種處理方案:

  • 失敗告警(快速發(fā)現(xiàn)問題):任務(wù)失敗時(shí),主動(dòng)向任務(wù)負(fù)責(zé)人發(fā)送告警通知,如郵件、短信等方式。這是一種常用的處理方案,原理和實(shí)現(xiàn)都比較簡單。負(fù)責(zé)人接收的告警郵件時(shí),通過人工的方式進(jìn)行故障處理,如手動(dòng)觸發(fā)一次任務(wù)執(zhí)行。
  • 失敗重試(快速解決問題):任務(wù)失敗時(shí),調(diào)度中心主動(dòng)嘗試觸發(fā)一次重試任務(wù)。優(yōu)點(diǎn)在于不需要人為接入,重試在一定程度上可以大大提高任務(wù)的成功率。但是,失敗重試需要注意限制重試次數(shù),否則將會(huì)導(dǎo)致”失敗-重試-失敗”的死循環(huán),造成資源浪費(fèi)。

路由策略

由于任務(wù)執(zhí)行器存在多個(gè)實(shí)例,調(diào)度器如何選擇任務(wù)執(zhí)行器同樣是個(gè)問題。

為每個(gè)任務(wù)配置不同的路由策略(為配置則使用默認(rèn)路由策略)

常見的策略如下:

  • 隨機(jī)策略
  • 輪訓(xùn)策略
  • 任務(wù)IDHash策略
  • 背壓策略(需要調(diào)度器與執(zhí)行器通訊報(bào)告執(zhí)行器未執(zhí)行任務(wù)數(shù)量)

阻塞處理策略

任務(wù)阻塞經(jīng)常發(fā)生在耗時(shí)任務(wù)場景中。舉個(gè)例子,假如一個(gè)索引同步任務(wù)每10min運(yùn)行一次,由于依賴的服務(wù)出現(xiàn)long service導(dǎo)致一次任務(wù)運(yùn)行了15min,那么任務(wù)下次觸發(fā)時(shí)將會(huì)遭遇阻塞。

在調(diào)度比較密集,而執(zhí)行器來不及處理的情況下,任務(wù)阻塞策略可以指導(dǎo)執(zhí)行器快速處理阻塞的觸發(fā)請求。

常見的阻塞策略有以下幾種:

  • 單機(jī)串行(默認(rèn)):調(diào)度請求進(jìn)入執(zhí)行器后,調(diào)度請求進(jìn)入FIFO隊(duì)列并以串行方式運(yùn)行;
  • 丟棄后續(xù)調(diào)度:調(diào)度請求進(jìn)入執(zhí)行器后,發(fā)現(xiàn)執(zhí)行器存在運(yùn)行的調(diào)度任務(wù),本次請求將會(huì)被丟棄并標(biāo)記為失??;
  • 覆蓋之前調(diào)度:調(diào)度請求進(jìn)入執(zhí)行器后,發(fā)現(xiàn)執(zhí)行器存在運(yùn)行的調(diào)度任務(wù),將會(huì)終止運(yùn)行中的調(diào)度任務(wù)并清空隊(duì)列,然后運(yùn)行本地調(diào)度任務(wù);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容