在系統中增加quartz定時任務集群,tomcat集群會多次執行,怎麼解決呢?

沈孟棟


做過類似的功能,不一定非得用分佈式定時任務,還是要結合項目實際來選擇具體的解決方案;從簡單的說起,給大家介紹幾個(不一定要選高大上的方案,適合最重要)。

比如數據庫中每天都會有一百萬條數據待處理,一個定時任務(記為A)要處理完這一百萬條數據,需要10個小時;如果想加快這個處理速度,我們首先能想到的是多部署一個批處理程序(記為B),這時候理論上需要10/2=5個小時,可以把任務都處理完。

方案一:待處理任務表增加一個處理標誌的字段,例如0=待處理,1=處理中,2=處理完成;當A任務取到待處理數據的時候,將此字段更新成1,處理完之後更新成2;當字段=1/2的時候,B任務不會取到這條數據;但是這種方法的問題極大,因為很容易發生一條待處理任務在被A查詢到,但是未更新處理狀態前,就被B任務取到,這樣就會造成重複處理的問題。

方案二:把處理任務進行人為的劃分,A處理一批數據,B處理一批數據。可以從純數據角度劃分,比如id%2=0的A處理,id%2=1的B處理,也可以從業務角度劃分,比如某個字段in(A,B,C)的A處理,某個字段in(X,Y,Z)的A處理;這樣做不會造成數據重複處理,但是也有一些問題:

  1. 數據不一定能夠平均分配,比如字段in(A,B,C)的數據有90萬條,字段in(X,Y,Z)的有10萬條。

  2. 難以擴展,因為條件是寫死的,所以如果要增加減少機器的話比較麻煩;

  3. 如果其中一臺機器掛掉,那麼這部分數據就不會處理。

方案三:方案一改進一下,增加分佈式鎖(可以是數據庫、Redis、ZK),誰能搶到鎖,誰才能提取待處理任務,並更新處理狀態,比如一次提取一萬行數據,並把這些數據的待處理狀態更新成【處理中】,然後把鎖釋放掉,再由其他的節點搶鎖。這種方案需要考慮的東西也不少:

  1. 要考慮鎖超期的問題:如果A搶到鎖,還沒釋放鎖之前A就掛掉了,那麼所有任務都會被卡主。

  2. 如果鎖超期被釋放掉,A處理到一半的任務還需要被其他任務處理(失效轉移)。

  3. 可以和方案二結合,做任務分片,批處理程序搶到鎖後,領取一個任務分片進行處理。

方案四:直接採用分佈式任務處理框架,我熟知的就是Elastic-Job了,它的功能更為強大,不過主要的功能嘛,你能理解前三個方案的話,這個方案也就容易理解了(基本上就是上面那些東西)。

我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。


會點代碼的大叔


這個問題本質上是在談分佈式任務的問題,我們從這個角度進行分析。


1 評估數據量

定時任務一般的使用場景是定時查詢出一批數據,對這一批數據進行業務操作。

根據數據量的大小決定是否使用分佈式任務,如果數據量不大或者實時性要求不高,單機任務就夠了。

如果數據量大就需要部署分佈式任務。分佈式集群中的節點對數據進行分片處理,即每個節點拿一部分數據進行業務處理。


2 僅解決併發問題方案

(1) Quartz + 分佈式鎖

假設定時任務部署了3臺機器,在任務啟動時3臺機器競爭分佈式鎖,誰競爭到誰就執行,剩下2臺不執行。分佈式鎖可以使用Redis或者Zookeeper

(2) 開關方案

方案一:配置文件中設置開關是否開啟,執行任務前讀取該開關,開啟則執行。這種方式實現比較簡單,但是如果需要換另外一臺機器執行,必須修改配置項併發布項目,維護成本較高

方案二:建一個數據庫配置表,配置表中配置可執行任務的機器標識,每臺機器執行前讀取這個配置,看看是否是本機,如果是則執行,否則不執行

方案三:Zookeeper做全局開關,開關內容是可執行任務的機器標識,原理同方案一


3 真正分佈式任務方案

(1) Quartz官方分佈式方案

我認為這種方式比較重,需要新建好幾張表

(2) Elastic Job(推薦)

噹噹網開源的一個分佈式調度解決方案,在業界比較通用


敬請關注

請點擊關注按鈕【IT徐胖子】會持續為大家奉獻互聯網和技術乾貨內容,感謝支持


IT徐胖子


定時任務對於服務器加載來看其實是一個服務,在集群中每個節點是一個獨立的應用,Quartz節點並不與其他節點通信,這導致如果不加控制就會多次執行,但要怎樣來控制它使其一個任務只執行一次呢?答案是分佈式鎖。

分佈式鎖的實現方式多種多樣。

最簡單的當然屬於quartz數據庫鎖:Quartz通過數據庫行級鎖來實現分佈式鎖(一種悲觀鎖),通過qrtz_locks表來控制線程對鎖的狀態獲取,也就是一個加鎖-操作-釋放的過程。

zookeeper實現分佈式鎖:利用zookeeper的存儲狀態節點的方式實現分佈式獨佔鎖,保證quartz的單點運行,利用zookeeper的特性,讓拿到鎖的quartz應用執行,沒拿到鎖的應用等待。

redis實現分佈式鎖:原來其實大同小異,通過redis控制狀態(鎖)與超時時間,拿到狀態的在超時時間內完成任務調度。沒拿到鎖的則等待。


各位條友們的看法呢?一起來說說?


谷友科技笑說


quartz支持基於各種關係型數據庫的集群,保證集群裡一個任務只會在一個節點執行,同時支持任務持久化,看下官方demo so easy


黑白人


用專門的任務管理器,elastic-job,xxl-job,jobx


31277201


加一個分佈式鎖就行了


gongjing2012


quartz支持分佈式定時任務,好好看下文檔


分享到:


相關文章: