背景
隨著互聯網的發展,應用服務中的定時任務數量日益增加,常規的垂直應用架構已無法應對,分布式服務架構勢在必行。同時,也迫切需要壹個分布式任務調度系統來管理分布式服務中的定時任務。
單壹應用架構
當網站流量很小時,只需壹個應用,將所有功能都部署在壹起,以減少部署節點和成本。此時,在該應用中的定時任務如果不多還好,但是壹旦比較多,則意味著每次更改壹個定時任務的執行時間,就需要重新部署壹遍整個應用,導致整個應用停滯壹段時間。
垂直應用架構
當訪問量逐漸增大,單壹應用增加機器帶來的加速度越來越小,將應用拆分為互不相幹的幾個應用來提升效率。此時,相應的任務也會被垂直拆分,每次更改任務帶來的影響相應減少。
分布式服務架構
當垂直應用越來越多,應用之間可能會出現不可避免的交互,此時,將核心業務抽取出來,形成單獨的服務,各式各樣的服務逐漸形成穩定的服務中心,使得前端應用能更快地響應多變的市場需求。此時,用於提高業務復用及整合的分布式服務框架是關鍵,同時,由於服務獨立,則壹般能做到定時任務獨立的情況,因此,任務的更改對於整體系統的影響小之又小。
分布式任務調度
在分布式服務架構的基礎上,由於獨立業務的數量可能很多,此時如果定時任務單獨在該服務中實現,很可能會出現難以管理的情況,且避免不了定時任務更改導致的業務重啟,因此,壹個獨立的分布式任務調度系統是很必要的,可以用來全局統籌管理所有的定時任務,同時,將任務的配置單獨抽離出來作為該分布式任務調度系統的功能,就能做到定時任務的更改不影響任何業務,也不影響整個系統。
架構設計
設計思想
以Dubbo核心,將調度單獨抽象出來,成為壹個調度中心,調度中心本身不承擔實現任何業務邏輯,只是單純依據調度配置來發起調度請求
將任務抽象成為ExecutorService,由任務執行者來實現具體的任務,並且負責接收調度請求並執行,這樣設計可以將任務與調度中心完全解耦,提高整個系統的擴展性,方便接入
將調度中心對任務執行者的壹些調用操作提取出來,形成壹個單獨的管理控制臺,可以用來查看任務執行情況,同時該管理控制臺通過H5實現,並提供對外Restful API,方便擴展與接入
通過各種中間件,實現壹些必須的操作,例如告警,監控,日誌收集統計等操作,完全對整個系統安全性,穩定性的保障
調度中心集群通過Zookeeper存儲每個Schedular的壹致性HashCode,以此來分配Job與Schedular之間的關系:新增的Job將會通過每個Schedular的壹致性HashCode獲取其對應的Job數,依據Job數的大小以及Schedular的相關屬性來計算每個Schedular的權重,根據權重的大小來確定當前新增的Job應該被分配到哪個Schedular上。
當新增Schedular之後,該新增的Schedular的Job正常為0,因此,正常狀態下,該新增的Schedular的權重會比較大。
同時,調度中心通過Zookeeper對Schedular實現主備切換,確保系統穩定性
系統組成
Schedular
基於Quartz實現調度,提供對執行者操作的接口,用於操作任務調度配置,調度觸發等操作;自身不參與任務邏輯的實現,不會受限於任務
執行者
負責接收調度中心發起的調度請求,實現相應業務邏輯,完成任務執行,同時會對任務邏輯進行切面處理,記錄相應日誌並在任務結束後發送給調度中心
管理控制臺
管理控制臺負責展示任務狀態,執行情況,任務執行日誌等報表數據,同時可以通過管理控制臺配置新增任務,操作任務的狀態,暫停/恢復等;另外,提供對外Restful API與H5的接入
Dubbo Monitor
實時監控調度中心接口調用情況,統計調度頻次,成功失敗,QPS等,能通過這些報表數據來優化任務調度,優化系統
ELK
通過ELK(ElasticSearch+Logstash+Kibana)來收集調度中心以及各執行機的執行日誌,並加以分析統計,形成報表,可以方便提供觀察
Alarm
報警系統,通過Chronograf控制臺配置告警規則,在出現問題時第壹時間通過Kapacitor進行郵件與短信報警,可以有效提高錯誤提示的及時性並且降低錯誤發生到錯誤解決過程中消耗的時間,降低生產環境造成的損失,告警數據通過業務儀表盤獲取。例如:可以配置線上機器的cpu當前使用率,設置閥值50%,策略為超過設置閥值時短信告警,此時當線上某臺機器cpu超過50%時,即會發送短信告警
業務儀表盤
通過打點的方式,來實時收集接口監控數據,通過logstash傳輸到kafka,通過kafka再分發到jstorm進行處理,處理完之後再存儲到influxdb,形成業務儀表盤,最後通過Grafana控制臺產生監控報表
配置中心
整個系統各服務,通過配置中心統壹管理相應配置,形成分布式配置管理機制,方便系統內各服務的配置壹致性以及準確性
在配置完之後,就可以實現自己的任務邏輯了
接入之後,可以通過日誌管理控制臺線上實時查看任務執行狀態
另外,由於有告警系統,在任務執行異常時,會產生告警郵件與短信,實時發送,告知任務接入者與相應研發人員
配置中心屬性配置
特性
支持動態暫停/恢復任務
任務狀態停止時,任務將不再被觸發,若任務在執行過程中被暫停,則正在執行的任務不會被阻塞(由於任務執行結果狀態中存在超時失敗狀態,因此如果點擊暫停按鈕時阻塞了當前正在執行的任務,會使當前任務的執行狀態變為超時,不符合超時狀態真正的意義),會延遲停止,即等到當前任務執行完再真正停止任務
調度中心基於Quartz實現,通過Zookeeper實現主備隔離,保證調度中心HA
當活躍節點宕機,冷備節點就會載入所有活躍節點中正在調度狀態的任務,成為新的活躍節點,保證任務調度的準確執行
執行機支持集群部署,任務分布式執行,通過調度中心統壹調度
執行機負載均衡,默認根據任務在某個執行機上的執行次數計算執行機調度權重,按照權重來選擇本次任務調度分發給哪臺執行機,實現負載均衡,可手動更改執行機選擇策略
執行機集群方式,
failover,failfast,failsafe,failback,forking,默認為failover(故障切換),調用失敗時,重試其他服務器;failfast(快速失敗),只會發起壹次調用,不會重試,失敗立即報錯;failsafe(失敗安全),出現異常時,直接忽略;failback(失敗恢復),調用失敗時,定時重發,直到成功,重啟會丟失; forking,並行調用多個執行機,只要壹個成功即返回
分片任務,支持任務分片,通過參數發送給任務執行機,執行機可以通過判斷參數來進行分片作業的開發,同時支持動態分片,以分片參數和執行機為緯度進行分片,支持動態擴容執行機以及分片參數
例如,某張訂單表按照訂單ID來進行簡單緯度分片,且以取模3來進行分片,則可以設置三個分片參數,(0,1,2),執行機在通過context拿到其中的壹個分片參數之後可以對該分片參數做判斷,來做具體的數據操作,例如當拿到的分片參數為0時,則對於0相應的分片做數據查詢操作,依次類推
再例如,某張訂單表按照訂單ID和Status來進行二維分片,ID取模以3來進行分片,狀態以成功,失敗兩種狀態來進行分片,此時就可以設置6個分片參數,({‘id’:0,’status’:0},{‘id’:1,’status’:0},{‘id’:2,’status’:0},{‘id’:0,’status’:1},{‘id’:1,’status’:1},{‘id’:2,’status’:1}),執行機在通過context拿到其中的壹個分片參數之後,就可以對其json參數進行判斷,來實現分片操作
任務執行壹致性,每次任務只會被壹個執行機所執行;對於分片任務,在執行機集群部署時,壹次任務調度將會廣播觸發對應集群中相應數量的執行器執行壹次任務,同時傳遞分片參數,可根據分片參數開發分片任務。
當分片參數大於執行器數量時,將會按照執行器路由策略,使得當前分片任務的某個或者某幾個執行機執行多個分片的任務
例如:當前分片任務分片參數為(a,b,c),當前任務執行機有3臺(A,B,C)時,則會均勻隨機得將分片參數發送給某壹臺執行機,且三臺執行機壹次只接收壹個分片參數,做壹次任務處理,即(a->A,b->B,c->C)|(a->A,b->C,c->B)|(a->B,b->A,c->C)|(a->B,b->C,c->A)|(a->C,b->A,c->B) |(a->C,b->B,c->A);
當任務執行機只有2臺(A,B)時,每次任務調度時,某臺執行機會收到兩個分片參數,並分別處理這兩個分片參數,即(a->A,b->B,c->A)|(a->A,b->B,c->B)|(a->B,b->A,c->A)|(a->B,b->A,c->B);
而當任務執行機大於分片參數個數,為4臺(A,B,C,D)時,(a->A,b->B,c->C)|(a->A,b->C,c->D)|(a->A,b->D,c->B)| (a->B,b->C,c->D)|(a->B,b->D,c->A)|(a->B,b->A,c->C)|(a->C,b->A,c->B)|(a->C,b->B,c->D)| (a->C,b->D,c->A)|(a->D,b->A,c->B)|(a->D,b->B,c->C)|(a->D,b->C,c->A),而統計下來,不管是執行機數目大於或者等於或者小於分片參數數目,被分發給執行機的分片參數始終是保持壹致的(每臺執行機接收到的總的分片參數是均勻的)
告警系統,系統接入內部告警系統,任務失敗時支持郵件,短信,釘釘,電話等告警
彈性擴容縮容,調度中心將會實時探測任務執行機,因此壹旦有執行機上線或者下線,都將會被探測到,而如果未被調度中心探測到,則可以進行手動探測執行機,而在探測到執行機之後,下次調度將會重新分配任務
任務依賴,支持配置任務依賴關系,當父任務在執行完成之後會自動觸發子任務的執行例如:有兩個任務,分別為A和B,而B的執行條件為確認A任務執行完,B才能執行,否則,B任務不執行,此時的依賴關系就是B任務依賴A任務,此時在A任務配置完之後,設置B任務為依賴任務,而依賴關系則是A;又例如有6個任務,分別是A1,A2,A3,A4,A5,B,而B任務的執行需要確保A1-5這5個任務都執行完,B任務才執行,此時,B的依賴關系就是B任務依賴於A1-5,此時在配置完A1-5這5個任務之後再設置B為依賴任務,依賴關系則是A1-5
支持運行時查看任務執行情況,任務數量,調用次數,執行器數量等統計信息異常執行恢復機制,有時會遇到不可控情況,即執行機在執行後的執行結果因為網絡斷開等不可控因素導致不能發送給調度中心,此時能通過異常執行恢復機制臨時記錄,在下次執行機正常啟動時重試發送給調度中心調度手動觸發手動執行,特殊需求下,可能會要求調度可以手動執行,例如調度任務失敗之後可能需要手動執行壹次調度來補償
並行/串行策略,當定時時間遠大於任務執行時間時,可以使用並行策略,任務異步調用執行,提高任務調度精確度;當任務執行時間可能大於定時時間,卻需要任務按照某個定時規則定時調度時,可以使用串行策略,調度中心調度的當前任務的上壹次觸發,如果沒有執行完,則當前執行機的下壹次定時時間點時不會被觸發,當且僅當任務執行結束,以防止某些持續性定時任務的時間不確定性導致異步觸發時的數據混亂的情況發生,例如:某壹任務的定時時間為10秒鐘,但是任務本身可能會出現執行超過10秒的情況,而超過時,如果出現兩個時間點的任務並行執行時會出現數據混亂的情況,此時就可以使用串行策略,確保當前執行機上壹個任務未執行完,不會觸發新的執行
支持調度接口數據監控,產生監控報表,便於觀測。
總結
對於互聯網公司來說,時間就是金錢,效率決定壹切。本系統在接入到8月初將近3個月的時間內,表現不凡,調度了約100萬次,給公司內部各服務實現任務調度提供了便利。
原文