分散式定時任務框架原理
分散式定時任務框架原理
1. 定時任務
定時任務非常常見,如定時清理狀態、定時生成訂單、定時處理日誌.....,總之定時任務使用得非常之廣泛,定時任務的框架也比較多,如crontab,quartz,spring-batch,elastic-job,dts,tbschedule等,框架還是比較多。今天重點介紹quartz,並將它引申到分散式環境下使用。
quartz在單機環境下支持得比較多,可以支持RAM和JDBC保存job運行相關的數據,它在分散式環境下展現得不是很好。單機下進行定時任務調度時,當數據量一大的時候,運行的job時間比較長,這時就要進行優化了。曾經遇到高峰期產生訂單800萬,老的邏輯運行要運行數小時,分析Job執行的情況後,發現是IO密集型 ,果斷採用多線程來處理,加上使用批量插入更新、預讀、去掉無用重複操作,同時硬碟換成SSD,整個優化下來提速40多倍!由之前數小時完成的任務變成在幾分鐘之內完成,大大的提升了運行速度。但如果數據量還在急劇增加,多線程模式下,job運行時間還會延長。
在大數據量下,處理的方法就是分片處理,多線程是單機下的分片處理,單機處理能力有限。在單機下進行任務調度存在兩個問題:
1)數據量一大,存在瓶頸;
2)任務調度和任務處理放在一起,這是兩個獨立的部分,可以拆分開。總結1:數據量大的任務,尤其是數據量達到千萬級別,只有分片處理,別無它法(單機已經做到了極限)
2. 分散式任務調度模式設計模式
2.1 調度與任務執行拆分
下面給出兩種模式:
1)quartz完成任務調度(單台,後面會引申到分散式環境下),job被喚醒後,會向集群組內發送請求,通過反射實例化任務,請注意,發送請求的時候會攜帶一些額外的數據過去,假設是用取余的方式,告訴每台機器select數據時,帶上這個條件去select數據,目的是數據不會被重複選擇出來。
2)quartz完成任務調度(單台,後面會引申到分散式環境下),job被喚醒後,會向集群中某一台機器發送請求,該機器接受到請求後,它就專門負責撈數據,然後通過metaq發送出去,其它節點監聽metaq消息,發現是自己要處理的(job名字就是tag),就接收消息並處理。
使用quartz的原因是它幫我們做什麼時候任務要執行,由它來完成調度。
正常調度的情況下,上面兩種模式都沒有問題,但出了異常情況下,就會有問題,比如發送消息的機器掛掉了,則該任務只執行了一部分,如果沒有良好的監控,根本就不知道Job執行有沒有執行完成,這兩種模式還存在優化的空間。
細心的同學,又會發現一個問題,我們的業務處理代碼是放在業務機器上的,難道新增加Job還要往quartz調度的執行上提交代碼嗎?非也,這裡使用到一個巧妙的地方,就是實現化JobDetail的時候,都寫一個Job,用這個Job替換所有的Job。
2.2 解決調度單點問題
經過第一步,把調度和執行分離後,調度單點是一個問題,如果它掛了,就完蛋了。如果把它放到分散式環境下進行調度呢?分散式鎖這時就發揮作用了,將上面的調度機器再部署2台(理倫上調度的機器不會多台),Job到點被喚醒後,三台機器上的TimerExecutor Job都會進行到execute()方法里,此時這三台機器都會去搶分散式鎖,誰搶到了,誰就來負責調度,驚不驚喜,用分散式鎖就搞定了!
到這裡了,有必要總結一下:
總結 2: 調度單點問題可以通過分散式鎖來實現,調度巧妙之處用一個Job映射成多個Job。 總結 3: 定時任務處理的三步曲:取數、處理、回寫,上面的兩種模式對應兩種取數試,一種是主動取數,第二種是被動接受數據。
3. 一種按照數據區間來完成批量任務調度執行的框架
大部分的批量任務是IO密聚型的,單台機器上執行使用多線程是會提升速度的,這裡會把集群分片+單機多線程都使用上去,這樣處理速度會更快。一般處理的數據集有一個範圍([min(Id),max[Id]]),在調度的時候就計算出來,然後按照10w的步長進行切割,得到多個區間,再把這些區間數據放到zookeeper上去,通知節點來取數據,執行完成後把對應的區間數據刪除,某個目錄下沒有數據了,說明整個job都執行完成了。節點拿到這個10w步長的數據,內部再按1w的步長來劃分,用10個線程來跑本次任務,達到集群分片執行和單機多線程執行。
總結 4: 利用集群分片+單機多線程來提升批量任務執行的效率
4. 總結
在梳理DTS框架的基礎上,總結分散式批量任務處理的思想,在實際的執行過程中,曾遇到了共享數據的問題,如何保證分配的數據間沒有交集(更多的體現在多表的處理),只能從共享的維度出發分割數據,分割出來的數據並不均勻,有共享數據是一個頭疼的問題,歡迎有好想法的同學可以交流這個問題。
推薦閱讀: