天天看點

淺談定時任務的分布式排程

單機定式任務排程的問題

在很多應用系統中我們常常要定時執行一些任務。比如,訂單系統的逾時狀态判斷、緩存資料的定時更新、定式給使用者發郵件,甚至是一些定期計算的報表等等。常見的處理方式有線程的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://www.cnblogs.com/haoxinyue/p/6886196.html