定時任務的分佈式調度

單機定式任務調度的問題

在不少應用系統中咱們經常要定時執行一些任務。好比,訂單系統的超時狀態判斷、緩存數據的定時更新、定式給用戶發郵件,甚至是一些按期計算的報表等等。常見的處理方式有線程的while(true) 和sleep組合、使用Timer定時器觸發任務又或者是使用quartz框架。貌似這些方法能夠完美的解決方案,爲何還須要分佈式呢?主要有以下兩點緣由:python

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

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

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

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-lite-console

 

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

 

Saturn

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

image

image

 

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

相關文章
相關標籤/搜索