1. 程式人生 > >定時任務的分布式調度

定時任務的分布式調度

設置 .com 交換 info 輪轉 web 自己 接受 console

轉自: https://www.cnblogs.com/haoxinyue/p/6886196.html

單機定式任務調度的問題

在很多應用系統中我們常常要定時執行一些任務。比如,訂單系統的超時狀態判斷、緩存數據的定時更新、定式給用戶發郵件,甚至是一些定期計算的報表等等。常見的處理方式有線程的while(true) 和sleep組合、使用Timer定時器觸發任務又或者是使用quartz框架。貌似這些方法可以完美的解決方案,為什麽還需要分布式呢?主要有如下兩點原因:

1.高可用:單機版的定式任務調度只能在一臺機器上運行,如果程序或者系統出現異常就會導致功能不可用。雖然可以在單機程序實現的足夠穩定,但始終有機會遇到非程序引起的故障,而這個對於一個系統的核心功能來說是不可接受的。

2.單機處理極限:原本1分鐘內需要處理1萬個訂單,但是現在需要1分鐘內處理10萬個訂單;原來一個統計需要1小時,現在業務方需要10分鐘就統計出來。你也許會說,你也可以多線程、單機多進程處理。的確,多線程並行處理可以提高單位時間的處理效率,但是單機能力畢竟有限(主要是CPU、內存和磁盤),始終會有單機處理不過來的情況。

這個時候就需要分布式的定時任務來實現了。業內常用的分布式定式任務解決方案主要有quartz、淘寶的TBSchedule和當當的elastic-job。

quartz的集群解決方案

quartz的單機版本大家應該比較熟悉,它的集群方案是使用數據庫來實現的。集群架構如下:

技術分享圖片

上圖三個節點在數據庫中都擁有同一份Job定義,如果某一個節點失效,那麽Job會在其他節點上執行。由於三個節點上的Job執行代碼是一樣的,那麽怎麽保證只有在一臺機器上觸發呢?答案是使用了數據庫鎖。在quartz的集群解決方案裏有張表scheduler_locks,quartz采用了悲觀鎖的方式對triggers表進行行加鎖,以保證任務同步的正確性。一旦某一個節點上面的線程獲取了該鎖,那麽這個Job就會在這臺機器上被執行,同時這個鎖就會被這臺機器占用。同時另外一臺機器也會想要觸發這個任務,但是鎖已經被占用了,就只能等待,直到這個鎖被釋放。之後會看trigger狀態,如果已經被執行了,則不會執行了。

簡單地說,quartz的分布式調度策略是以數據庫為邊界資源的一種異步策略。各個調度器都遵守一個基於數據庫鎖的操作規則從而保證了操作的唯一性。同時多個節點的異步運行保證了服務的可靠。但這種策略有自己的局限性:集群特性對於高CPU使用率的任務效果很好,但是對於大量的短任務,各個節點都會搶占數據庫鎖,這樣就出現大量的線程等待資源。這種情況隨著節點的增加會越來越嚴重。

另外,quartz的分布式只是解決了高可用的問題,並沒有解決任務分片的問題,還是會有單機處理的極限。

TBSchedule

TBSchedule是一款非常優秀的高性能分布式調度框架,廣泛應用於阿裏巴巴、淘寶、支付寶、京東、聚美、汽車之家、國美等很多互聯網企業的流程調度系統。tbschedule在時間調度方面雖然沒有quartz強大,但是它支持分片功能。和quartz不同的是,tbschedule使用ZooKeeper來實現任務調度的高可用和分片。

TBSchedule的分布式機制是通過靈活的Sharding方式實現的,分片的規則由客戶端決定,比如可以按所有數據的ID按10取模分片、按月份分片等等。TBSchedule的宿主服務器可以進行動態擴容和資源回收,這個特點主要是因為它後端依賴的ZooKeeper,這裏的ZooKeeper對於TBSchedule來說是一個NoSQL,用於存儲策略、任務、心跳信息數據,它的數據結構類似文件系統的目錄結構,它的節點有臨時節點、持久節點之分。調度引擎啟動後,隨著業務量數據量的增多,當前Cluster可能不能滿足目前的處理需求,那麽就需要增加服務器數量,一個新的服務器上線後會在ZooKeeper中創建一個代表當前服務器的一個唯一性路徑(臨時節點),並且新上線的服務器會和ZooKeeper保持長連接,當通信斷開後,節點會自動摘除。

TBSchedule會定時掃描當前服務器的數量,重新進行任務分配。TBSchedule不僅提供了服務端的高性能調度服務,還提供了一個scheduleConsole的war包,隨著宿主應用的部署直接部署到服務器,可以通過web的方式對調度的任務、策略進行監控管理,以及實時更新調整。

elastic-job

Elastic-Job當當開源的分布式調度解決方案,由兩個相互獨立的子項目Elastic-Job-Lite和Elastic-Job-Cloud組成。Elastic-Job-Lite定位為輕量級無中心化解決方案,使用jar包的形式提供分布式任務的協調服務。一般我們只要使用Elastic-Job-Lite就好。

Elastic-Job-Lite並沒有宿主程序,而是基於部署作業框架的程序在到達相應時間點時各自觸發調度。它的開發也比較簡單,引用Jar包實現一些方法即可,最後編譯成Jar包運行。Elastic-Job-Lite的分布式部署全靠ZooKeeper來同步狀態和原數據。實現高可用的任務只需將分片總數設置為1,並把開發的Jar包部署於多個服務器上執行,任務將會以1主N從的方式執行。一旦本次執行任務的服務器崩潰,其他執行任務的服務器將會在下次作業啟動時選擇一個替補執行。如果開啟了失效轉移,那麽功能效果更好,可以保證在本次作業執行時崩潰,備機之一立即啟動替補執行。

Elastic-Job-Lite的任務分片也是通過ZooKeeper來實現,Elastic-Job並不直接提供數據處理的功能,框架只會將分片項分配至各個運行中的作業服務器,開發者需要自行處理分片項與真實數據的對應關系。框架也預置了一些分片策略:平均分配算法策略,作業名哈希值奇偶數算法策略,輪轉分片策略。同時也提供了自定義分片策略的接口。

另外Elastic-Job-Lite還提供了一個任務監控和管理界面:Elastic-Job-Lite-Console。它和Elastic-Job-Lite是兩個完全不關聯的應用程序,使用ZooKeeper來交換數據,管理人員可以通過這個界面查看、監控和管理Elastic-Job-Lite的任務,必要的時候還能手動觸發任務。

技術分享圖片

elastic-job結合了quartz非常優秀的時間調度功能,並且利用ZooKeeper實現了靈活的分片策略。除此之外,還加入了大量實用的監控和管理功能,以及其開源社區活躍、文檔齊全、代碼優雅等優點,是分布式任務調度框架的推薦選擇。

Saturn

Saturn是唯品會在github開源的一款分布式任務調度產品。它是基於當當elastic-job來開發的,其上完善了一些功能和添加了一些新的feature。目前在github上開源大半年,470個star。Saturn的任務可以用多種語言開發比如python、Go、Shell、Java、Php。其在唯品會內部已經發部署350+個節點,每天任務調度4000多萬次。同時,管理和統計也是它的亮點。

技術分享圖片

技術分享圖片

有興趣的同學可以從https://github.com/vipshop/Saturn 上了解更加詳細的信息。

定時任務的分布式調度