伺服器採用了負載均衡,有兩台伺服器,部署的**一樣,所以裡面的定時任務在某一時間會被同時執行,這就導致了很多其他意外的發生,想要解決的問題基本就三個:單點執行,故障轉移,服務狀態。這裡對比一下網上找的幾種方案,:
(1)只在一台伺服器上部署該定時任務**。
優點:解決方法容易理解 缺點:部署麻煩,需要多套**,且當這台伺服器出問題時就沒定時任務了。
(2)在定時任務**上加上某個特定的ip限制,僅某個ip的伺服器能執行該定時任務。
優點:解決方法容易理解,部署簡單,不需要多套**。 缺點:同上,只能規定一台伺服器執行,傳送故障時就沒辦法了。
(3)利用資料庫的共享鎖事務管理機制來執行定時任務。
原理:在資料庫中新建一張表定時任務表,儲存了上次執行定時任務的ip位址(ip),任務名稱(task_name),是否正在執行(execute)。原部落格用**的方式解釋了自己的思路,這裡我用文本來總結一下:
集群中的所有伺服器都是走以下流程
第一步:查詢資料庫的定時任務表。
第二步:檢查是否有機器在執行定時任務。檢查方法:update定時任務表的excute欄位為1(1為執行中,0為未執行)、ip為自己的ip,如果update失敗,則證明有機器在執行該定時任務,該機器的定時任務就不執行了,成功則進行第三步。
第三步:執行定時任務的具體內容。
第四步:還原excute欄位為0。
以上是該方案的流程,利用了mysql的共享鎖機制判斷,通過是否更新成功來判斷是否有機器正在執行定時任務,這種方案可以保證任務只執行一次,且只要集群中有一台伺服器是好的,就會執行任務。方案挺好,暫時想不到有啥缺點,可能增加了資料庫的負擔算乙個吧....
(4)利用redis資料庫。
參考:原理:和第三種差不多,只是通過redis的key-value來儲存任務名--執行ip。執行定時任務前先查詢redis是否有改任務的值,沒有就自己 執行,並插入新的key-vale。有的話就檢視ip是否是自己,是的話就執行,不是的話就 證明有其他機器在執行,自己就不執行啦。過期時間可以自己設定,方便有機器出故障時候可以轉移機器執行任務。
優點:利用了redis的自動過期機制實現了轉移故障機器的問題,比較簡單,而且redis的訪問速度也很快。
缺點:這裡沒有事務管理機制,訪問redis的時候,一定會出現高併發的情況,所以得自己實現redis的共享鎖機制。
(5)利用quartz集群分布式(併發)部署解決方案。
參考:quartz有很成熟的分布式併發部署定時任務的解決方案了,但是配置比較複雜,且需要新建恨的資料庫表,這裡就不詳細寫了(好吧,我也沒認真看....)
綜上所述,我覺得第三種方案適合小型的專案去做,大的專案最好用quartz去做。
在實現的過程中又發現,同一臺伺服器上的不同版本之間也會發生cron重複執行的問題,所以不僅考慮不同伺服器的問題,還得考慮不同版本之間的問題。
防止 crontab 定時任務重複執行
前言 crontab 定時任務很好使用,它的定時是很強硬的,直接跟系統時間打交道,不會去管程式本身執行是否需要時間。舉個栗子 乙個指令碼執行需要 1 小時,使用 crontab 每隔2小時執行一次,一般情況下下次執行指令碼時上次指令碼執行肯定是跑完了的 但是,假如,程式卡住了呢?下次執行時上次指令碼...
集群環境下如何防止定時任務重複執行?
起因 最近做專案是遇到這樣乙個問題 系統需要在每天的16 00向一些符合特定條件的使用者傳送乙份郵件,傳送成功後修改掉資料庫中對應資料的標誌位。本來是沒有問題的,但後來系統被部署到了集群環境下,導致每天會向這些使用者傳送多次同樣的資料,遭到了客戶的抱怨。解決 下面來介紹一下處理這種問題的解決辦法 1...
集群環境下如何防止定時任務重複執行?
起因 最近做專案是遇到這樣乙個問題 系統需要在每天的16 00向一些符合特定條件的使用者傳送乙份郵件,傳送成功後修改掉資料庫中對應資料的標誌位。本來是沒有問題的,但後來系統被部署到了集群環境下,導致每天會向這些使用者傳送多次同樣的資料,遭到了客戶的抱怨。解決 下面來介紹一下處理這種問題的解決辦法 1...