做業即定時任務。通常來講,系統可以使用消息傳遞代替部分使用做業的場景。二者確有類似之處。可互相替換的場景,如隊列表。將待處理的數據放入隊列表,而後使用頻率極短的定時任務拉取隊列表的數據並處理。這種狀況使用消息中間件的推送模式可更好的處理實時性數據。並且基於數據庫的消息存儲吞吐量遠遠小於基於文件的順序追加消息存儲。java
(點擊放大圖像)git
但在某些場景下則不能互換:github
a) 時間驅動 OR 事件驅動:內部系統通常能夠經過事件來驅動,但涉及到外部系統,則只能使用時間驅動。如:抓取外部系統價格。每小時抓取,因爲是外部系統,不能像內部系統同樣發送事件觸發事件。web
b) 批量處理 OR 逐條處理:批量處理堆積的數據更加高效,在不須要實時性的狀況下比消息中間件更有優點。並且有的業務邏輯只能批量處理,如:電商公司與快遞公司結算,一個月結算一次,而且根據送貨的數量有提成。好比,當月送貨超過1000則額外給快遞公司多1%的快遞費。spring
c) 非實時性 OR 實時性:雖然消息中間件能夠作到實時處理數據,但有的狀況並不須要。如:VIP用戶降級,若是超過1年無購買行爲,則自動降級。這類需求沒有強烈的時間要求,不須要按照時間精確的降級VIP用戶。數據庫
d) 系統內部 OR 系統解耦:做業通常封裝在系統內部,而消息中間件可用於系統間解耦。服務器
a) Quartz:Java事實上的定時任務標準。但Quartz關注點在於定時任務而非數據,並沒有一套根據數據處理而定製化的流程。雖然Quartz能夠基於數據庫實現做業的高可用,但缺乏分佈式並行調度的功能。網絡
b) TBSchedule:阿里早期開源的分佈式任務調度系統。代碼略陳舊,使用timer而非線程池執行任務調度。衆所周知,timer在處理異常情況時是有缺陷的。並且TBSchedule做業類型較爲單一,只能是獲取/處理數據一種模式。還有就是文檔缺失比較嚴重。多線程
c) Crontab:Linux系統級的定時任務執行器。缺少分佈式和集中管理功能。框架
綜上所述,當前存在的做業系統缺乏分佈式、並行調度、彈性擴容縮容、集中管理、定製化流程型任務等功能,因此須要一個新的做業系統完善這些功能。
修改開源產品和基於開源產品從新搭建,是兩種可行性較高的方案。
修改開源產品可控性較低,且通常都是針對於某些特定功能,因此咱們採用將成熟的開源產品做爲積木,在其之上從新封裝,搭建一個嶄新的產品,並命名爲elastic-job。
elastic-job主要的設計理念是無中心化的分佈式定時調度框架,思路來源於Quartz的基於數據庫的高可用方案。但數據庫沒有分佈式協調功能,因此在高可用方案的基礎上增長了彈性擴容和數據分片的思路,以便於更大限度的利用分佈式服務器的資源。
a) 分佈式:重寫Quartz基於數據庫的分佈式功能,改用Zookeeper實現註冊中心。
b) 並行調度:採用任務分片方式實現。將一個任務拆分爲n個獨立的任務項,由分佈式的服務器並行執行各自分配到的分片項。
c) 彈性擴容縮容:將任務拆分爲n個任務項後,各個服務器分別執行各自分配到的任務項。一旦有新的服務器加入集羣,或現有服務器下線,elastic-job將在保留本次任務執行不變的狀況下,下次任務開始前觸發任務重分片。
d) 集中管理:採用基於Zookeeper的註冊中心,集中管理和協調分佈式做業的狀態,分配和監聽。外部系統可直接根據Zookeeper的數據管理和監控elastic-job。
e) 定製化流程型任務:做業可分爲簡單和數據流處理兩種模式,數據流又分爲高吞吐處理模式和順序性處理模式,其中高吞吐處理模式能夠開啓足夠多的線程快速的處理數據,而順序性處理模式將每一個分片項分配到一個獨立線程,用於保證同一分片的順序性,這點相似於kafka的分區順序性。
a) 失效轉移:彈性擴容縮容在下次做業運行前重分片,但本次做業執行的過程當中,下線的服務器所分配的做業將不會從新被分配。失效轉移功能能夠在本次做業運行中用空閒服務器抓取孤兒做業分片執行。一樣失效轉移功能也會犧牲部分性能。
b) Spring命名空間支持:elastic-job能夠不依賴於spring直接運行,可是也提供了自定義的命名空間方便與spring集成。
c) 運維平臺:提供web控制檯用於管理做業。
a) 穩定性:在服務器無波動的狀況下,並不會從新分片;即便服務器有波動,下次分片的結果也會根據服務器IP和做業名稱哈希值算出穩定的分片順序,儘可能不作大的變更。
b) 高性能:同一服務器的批量數據處理採用自動切割並多線程並行處理。
c) 靈活性:全部在功能和性能之間的權衡,均可經過配置開啓/關閉。如:elastic-job會將做業運行狀態的必要信息更新到註冊中心。若是做業執行頻度很高,會形成大量Zookeeper寫操做,而分佈式Zookeeper同步數據可能引發網絡風暴。所以爲了考慮性能問題,能夠犧牲一些功能,而換取性能的提高。
d) 冪等性:elastic-job可犧牲部分性能用以保證同一分片項不會同時在兩個服務器上運行。
e) 容錯性:做業服務器和Zookeeper斷開鏈接則當即中止做業運行,用於防止分片已經從新分配,而腦裂的服務器仍在繼續執行,致使重複執行。
elastic-job採用去中心化設計,主要分爲註冊中心,數據分片,分佈式協調,定時任務處理和定製化流程型任務等模塊。
a) 去中心化
去中心化指elastic-job並沒有調度中心這一律念,每一個運行在集羣中的做業服務器都是對等的,節點之間經過註冊中心進行分佈式協調。但elastic-job有主節點的概念,主節點用於處理一些集中式任務,如分片,清理運行時信息等,並沒有調度功能,定時調度都是由做業服務器自行觸發。
下面對比一下各自的優缺點:
|
中心化 |
去中心化 |
實現難度 |
高 |
低 |
部署難度 |
高 |
低 |
觸發時間統一控制 |
能夠 |
不能夠 |
觸發延遲 |
有 |
無 |
異構語言支持 |
容易 |
困難 |
b) 註冊中心
註冊中心模塊目前直接使用zookeeper,用於記錄做業的配置,服務器信息以及做業運行狀態。Zookeeper雖然很成熟,但原理複雜,使用較難,在海量數據支持的狀況下也會有性能和網絡問題。目前elastic-job已經抽象出注冊中心的接口,下一步將會考慮支持多註冊中心,如etcd,或由用戶自行實現註冊中心。無臨時節點和監聽機制的註冊中心須要自行實現定時心跳監測等功能。
c) 數據分片
數據分片是elastic-job中實現分佈式的重要概念,將真實數據和邏輯分片對應,用於解耦做業框架和數據的關係。做業框架只負責將分片合理的分配給相關的做業服務器,而做業服務器須要根據所分配的分片匹配數據進行處理。服務器分片目前都存儲在註冊中心中,各個服務器根據本身的IP地址拉取分片。
d) 分佈式協調
分佈式協調模塊用於處理做業服務器的動態擴容縮容。一旦集羣中有服務器發生變化,分佈式協調將自動監測並將變化結果通知仍存活的做業服務器。協調時將會涉及主節點選舉,重分片等操做。目前使用的Zookeeper的臨時節點和監聽器實現主動檢查和通知功能。
e) 定時任務處理
定時任務處理根據cron表達式定時觸發任務,目前有防止任務同時觸發,錯過任務重出發等功能。主要仍是使用Quartz自己的定時調度功能,爲了便於控制,每一個任務都使用獨立的線程池。
f) 定製化流程型任務
定製化流程型任務將定時任務分爲多種流程,有不經任何修飾的簡單任務;有用於處理數據的fetchData/processData的數據流任務;之後還將增長消息流任務,文件任務,工做流任務等。用戶能以插件的形式擴展並貢獻代碼。
將使用elastic-job框架的jar/war鏈接同一個基於Zookeeper的註冊中心便可。
elastic-job的開源主要是爲了反饋社區。開源短短兩個月,咱們收到了不少朋友的反饋和支持,很是感謝。技術類開源項目和通常的業務型項目不一樣,更須要對代碼和質量的控制,咱們總結出如下幾點:
a) 用心寫代碼,用代碼講故事。代碼是項目的惟一核心和產出,任何一行的代碼都須要用心思考優雅性,可讀性,合理性。
a) 代碼整潔乾淨到極致。只有代碼漂亮整潔,其餘開源愛好者才願意閱讀代碼,進而找出項目中的bug和貢獻高質量代碼。
b) 極簡代碼, 高度複用,無重複代碼和配置。Java生態圈的特色是高質量的開源產品極多。咱們儘可能考慮複用輪子,好比項目中大量用到lombok簡化代碼;但也不會無原則的使用開源產品,咱們傾向於把開源產品分爲積木類和大廈類。項目中通常只考慮使用積木類搭建屬於咱們本身的大廈,而不會直接用其餘已成型的大廈。
c) 單一需求可不考慮擴展性;兩個相似需求時再提煉。
d) 模塊抽象劃分合理。
e) 如無特殊理由, 測試需全覆蓋。elastic-job核心模塊的測試覆蓋率是95%以上。
f) 對質量的定義。代碼可讀性 > 代碼可測性 > 模塊解耦設計 > 功能正確性 > 性能 > 功能可擴展性。只有代碼可讀,可測試,可100%掌控,項目纔可持續發展。功能有缺陷能夠修復,性能不夠能夠優化,而代碼不清晰則項目會漸漸變爲黑盒。因此對於框架類產品,咱們認爲質量 > 時間 > 成本。
g) 文檔清晰。
目前的elastic-job定位是一個基於java的定時任務調度框架,將來想發展成爲支持異構語言,高度靈活,可自定製的定時任務調度產品。
a) 異構語言支持。目前採用的無中心設計,難於支持多語言,考慮調度中心的可行性。
b) 監控體系有待提升,目前只能經過註冊中心作簡單的存活和數據積壓監控。將來須要作的監控部分有:
增長可監控維度,如做業運行時間等。
基於JMX的內部狀態監控。
基於歷史的全量數據監控,將全部監控數據經過flume等形式發到外部監控中心,提供實時分析功能。
c) 多種註冊中心支持。
c) 增長任務工做流,如任務依賴,初始化任務,清理任務等。
d) 失效轉移功能的實時性提高。
e) 更多做業類型支持,如文件,MQ等類型做業的支持。
f) 更多分片策略支持。
elastic-job本來是噹噹java應用框架ddframe的一部分,本名dd-job。
ddframe包括編碼規範,開發框架,技術規範,監控以及分佈式組件。
噹噹但願將ddframe的各個模塊與公司環境解耦並開源以反饋社區。以前開源的Dubbo擴展版本DubboX便是dd-soa的核心模塊。而本次介紹的elastic-job則是dd-job的開源部分,其中監控(但開源了監控方法)和ddframe核心接入等部分並未開源。