叢集伺服器定時任務重複執行的解決方案
伺服器採用了負載均衡,有兩臺伺服器,部署的程式碼一樣,所以裡面的定時任務在某一時間會被同時執行,這就導致了很多其他意外的發生,想要解決的問題基本就三個:單點執行,故障轉移,服務狀態。這裡對比一下網上找的幾種方案,:
(1)只在一臺伺服器上部署該定時任務程式碼。
優點:解決方法容易理解 缺點:部署麻煩,需要多套程式碼,且當這臺伺服器出問題時就沒定時任務了。
(2)在定時任務程式碼上加上某個特定的ip限制,僅某個ip的伺服器能執行該定時任務。
優點:解決方法容易理解,部署簡單,不需要多套程式碼。 缺點:同上,只能規定一臺伺服器執行,傳送故障時就沒辦法了。
(3)利用資料庫的共享鎖事務管理機制來執行定時任務。
參考部落格:https://blog.csdn.net/u012881584/article/details/70194237
原理:在資料庫中新建一張表定時任務表,儲存了上次執行定時任務的ip地址(ip),任務名稱(task_name),是否正在執行(execute)。原部落格用程式碼的方式解釋了自己的思路,這裡我用文字來總結一下:
叢集中的所有伺服器都是走以下流程
第一步:查詢資料庫的定時任務表。
第二步:檢查是否有機器在執行定時任務。檢查方法:update定時任務表的excute欄位為1(1為執行中,0為未執行)、ip為自己的ip,如果update失敗,則證明有機器在執行該定時任務,該機器的定時任務就不執行了,成功則進行第三步。
第三步:執行定時任務的具體內容。
第四步:還原excute欄位為0。
以上是該方案的流程,利用了mysql的共享鎖機制判斷,通過是否更新成功來判斷是否有機器正在執行定時任務,這種方案可以保證任務只執行一次,且只要叢集中有一臺伺服器是好的,就會執行任務。方案挺好,暫時想不到有啥缺點,可能增加了資料庫的負擔算一個吧....
(4)利用redis資料庫。
參考:https://www.jianshu.com/p/48c5b11b80cd
原理:和第三種差不多,只是通過redis的key-value來儲存任務名--執行ip。執行定時任務前先查詢redis是否有改任務的值,沒有就自己 執行,並插入新的key-vale。有的話就檢視ip是否是自己,是的話就執行,不是的話就 證明有其他機器在執行,自己就不執行啦。過期時間可以自己設定,方便有機器出故障時候可以轉移機器執行任務。
優點:利用了redis的自動過期機制實現了轉移故障機器的問題,比較簡單,而且redis的訪問速度也很快。
缺點:這裡沒有事務管理機制,訪問redis的時候,一定會出現高併發的情況,所以得自己實現redis的共享鎖機制。
(5)利用quartz叢集分散式(併發)部署解決方案。
參考:https://www.tuicool.com/articles/B3qeUrB
quartz有很成熟的分散式併發部署定時任務的解決方案了,但是配置比較複雜,且需要新建恨的資料庫表,這裡就不詳細寫了(好吧,我也沒認真看....)
綜上所述,我覺得第三種方案適合小型的專案去做,大的專案最好用quartz去做。
在實現的過程中又發現,同一臺伺服器上的不同版本之間也會發生cron重複執行的問題,所以不僅考慮不同伺服器的問題,還得考慮不同版本之間的問題。
作者:歐陽的部落格
連結:https://www.jianshu.com/p/fc345064767c
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。