關注“Java藝術”一起來充電吧!
XXL-JOB
是一個代碼開源的分佈式定時任務調度平臺。XXL-JOB
支持多種模式執行定時任務,如直接執行任務腳本代碼、通過commandJobHandler
調用任務接口、使用@XxlJob
註解註冊JobHandler
。
我們舊的定時任務項目是通過提供接口由XXL-JOB
定時調用commandJobHandler
,再由commandJobHandler
執行shell
命令調用接口完成,雖然不是直接調用接口,但也可以說接口就是定時任務。
這種方式有利也有弊。團隊成員可能在編寫接口時,疏忽了接口執行耗時帶來的影響,如因項目設置http
超時導致XXL-JOB
認爲任務執行失敗,或是每個接口都需要手動將任務放入線程池異步執行,意味着任務執行成功或是失敗XXL-JOB
將無法得知,放入自定義的線程池執行日記無法被XXL-JOB
收集。我們也想將一些耗時、耗內存的任務實現分片執行,讓定時任務項目能夠支持橫向擴展。
爲解決這些問題,我們考慮將定時任務項目重構,並由原來的SSM
框架切換到Spring Boot
框架。但由於舊項目已有七八十個定時任務,全部遷移到新的框架上不現實,因此我們也放棄替換其它分佈式定時任務調度框架的想法,轉而想通過基於XXL-JOB
進行二次開發,解決我們在定時任務上遇到的一些問題。
xxl-job-onion
XXL-JOB-Onion now means XXL-JOB eXtensions. :)
XXL-JOB-Onion
是基於XXL-JOB
的二次開發,加入一些定製化功能。
1
二次開發添加的功能
基於XXL-JOB 2.2.0
版本進行二次開發
添加
ONION_BEAN
運行模式,強制使用分片策略;ONION_BEAN
模式改用線程池執行任務;ONION_BEAN
模式的阻塞處理策略放棄單機串行策略;告警模塊實現告警等級區分,一級告警短信發送;
爲
ONION_BEAN
模式提供@NotNeedShard
註解,當使用註解聲明任務不需要分片執行時, 如果執行器的可用數量大於1
,則使用一致性HASH
路由策略;
2
關於ONION_BEAN模式的疑問
爲什麼添加
ONION_BEAN
模式?ONION_BEAN
運行模式與其它運行模式有什麼不同?
使用BEAN
運行模式可通過在方法上添加@XxlJob
將任務註冊到admin
,但這種方式對開發人員的約束不夠強力,給開發人員自由可能就會給項目後期水平擴展節點實現任務分片執行帶來更多的難題。因此,我們放棄了XXL-JOB
提供的BEAN
模式,添加新的ONION_BEAN
運行模式。
爲了實現讓團隊成員開發定時任務時,必須通過實現接口來開發JobHandler
。除了在接口參數上強制開發者考慮任務分片執行外,還有一個目的就是限制一個類只能寫一個Job
。我們舊的定時任務項目很多類都是幾千行代碼的,一堆的任務在一個類中,失去了代碼的可讀性。因此使用實現接口的方式還能強制一個類只能編寫一個定時任務,在框架層實現代碼可讀性。當然,缺點就是類增多。
ONION_BEAN
模式強制考慮任務分片是出於讓定時任務項目支持水平擴展的考慮,也支持將一個重的定時任務項目按業務拆分。隨着集團內部業務的發展, 後期定時器會越來越多,並且任務處理的數據量也會越來越大。任務分片執行爲項目帶來擴展性的同時,分片執行可讓多臺機器分擔一臺機器的工作,提升任務的完成速度,從而避免一個任務的執行卡到下一個週期,導致原本多個週期的任務堆積在一個週期下執行的情況。比如12:30
、12:35
、12:40
三個週期的任務由於第一個週期沒執行完,後面的任務都在等待,這對一些實時性要求高的任務是個痛點。
ONION_BEAN
模式改變XXL-JOB
原有運行模式爲每個任務創建一個線程的做法,改爲使用非固定線程池執行JobHandler
。我們都知道,在有限資源,如CPU
、內存的情況下,線程數會有一個臨界點,超過這個臨界點時,再添加線程適得其反。因此使用線程池,可在線程池滿後拒絕任務的提交,讓該分片任務路由到其它空閒節點上執行,遺憾的是XXL-JOB
的分片模式現在還不支持這點,我們計劃在XXL-JOB-ONION的後續版本支持。
爲什麼強制當使用
ONION_BEAN
運行模式時只能選擇分片執行策略?
ONION_BEAN
運行模式把需要分片執行的任務與不需要分片執行的任務的考慮權重互換了,通過約定開發JobHandler
時必須通過實現接口的方式,在接口的方法上添加分片參數,強調團隊開發人員在開發定時任務JobHandler
時,需優先考慮讓任務支持分片執行。
既然要強制使用分片策略,又提供
@NotNeedShard
註解支持任務單機運行,這看似很矛盾,爲什麼這麼做呢?
選擇ONION_BEAN
運行模式,執行策略必須選擇分片策略。但由於不是所有任務都需要分片執行,如果不需要分片執行的情況下,還使用分片策略路由,那麼會導致所有的不需要分片執行的任務都被分配到同一臺機器上執行,導致某個執行器所在的機器資源消耗過大,因此,我們爲不需要分片執行的任務提供@NotNeedShard
註解,當任務有@NotNeedShard
註解時,且執行器的可用數量大於1
時,不走分片路由邏輯,而是使用一致性HASH路由。
3
告警模塊做了哪些修改?
告警模塊實現等級區分,一級告警發送短信通知,二級告警發送郵件通知,其它告警當前處理策略爲忽略,後續可能將多個三級告警合併爲一個告警發送郵件通知。同一個任務如果升級到一級告警,且後續還連續失敗,也只會觸發一次短信發送。
當前是如何區分告警等級的?每個任務都會有一個告警等級的升級過程:
如果週期爲秒鐘,則判斷是否連續失敗60次及以上,是則升級爲二級告警;
如果週期爲分鐘,則判斷是否連續失敗3次及以上,是則升級爲二級告警,連續失敗5次及以上升級爲一級告警;
如果週期爲小時,則判斷是否連續失敗1次及以上,是則升級爲二級告警,連續失敗3次及以上升級爲一級告警;
如果週期爲一天或以上,直接升級爲一級告警。
告警等級的評判由評判器實現,並使用責任鏈模式(或者說是過濾器)支持多個評判器共存。評判器支持排序,目前僅提供OnionAlarmLevelAdjudicator
告警等級批評器,如果想要覆蓋OnionAlarmLevelAdjudicator
評判器,可自行添加告警等級評判器,將排序值設置比OnionAlarmLevelAdjudicator
評判器的排序值小即可,OnionAlarmLevelAdjudicator
的排序值默認爲整型的最大值。
4
XXL-JOB分片策略的實現
XXL-JOB
的分片調度策略實現非常簡單,分片總數就是當前註冊的集羣節點數量,通過for
循環調用所有節點執行任務。
當一個任務執行完成時,會異步回傳任務的執行結果,XXL-JOB
通過回傳的結果判斷一個任務是否執行成功。當任務回傳結果爲失敗時,根據是否配置失敗重試次數,決定是否需要重新觸發任務執行。在分片模式下,也會爲每個分片任務添加一條XxlJobLog
記錄,當某個分片執行失敗時,重試策略只重試失敗的分片。
5
我們的執行器項目代碼開發規範
定時任務開發規範
按業務分包,如訂單相關定時器存放
order
包;定時任務需實現
OnionShardingJobHandler
接口,參考DemoJob
;確定不需要分片執行的定時任務使用
@NotNeedShard
註解聲明,參考NotNeedShardDemoJob
;
單元測試規範
每個定時任務對應一個測試類或者每個業務對應一個測試類,測試類所在包名與源碼所在包名保持一致;
定時任務必須經過單元測試通過後才能提交代碼;
END
目前尚處於測試階段,兩天時間從開始看源碼到改好測試!
公衆號:Java藝術
掃碼關注最新動態