分佈式定時任務原理以及實現
一、單機指定時間執行定時任務實現方式
- Timer運行機制
- ScheduledThreadPoolExecutor的運行機制
- 原理圖
- Leader/Follower模式
- Timer和ScheduledThreadPoolExucutor區別
- Timer是基於絕對時間,ScheduledThreadPoolExucutor基於相對時間
- Timer是單線程,ScheduledThreadPoolExucutor是多線程
- Timer運行發生異常,整個TimerThread崩潰,而ScheduledThreadPoolExucutor對異常進行捕獲
- 自行實現指定時間執行的定時任務
- 建立數據庫定時任務表,用戶存入要執行的定時任務,業務ID
- 定義Producer類,用於生產指定定時任務,往延遲隊列裏寫入數據,指定的毫秒時間戳
- 定義Consumer接口,自身業務可以通過實現Consumer接口消費隊列中的數據
- 定義SpringBoot自啓動方法,死循環從延遲隊列中取最小時間戳數據,與當前時間進行對比如果小於則開始執行,休眠100ms繼續下一次循環
- Quartz實現
二、分佈式指定時間執行的定時任務實現方式(自行Redis實現)
- 流程設計分析
- 因爲是應用是分佈式部署,所以需要考慮分佈式鎖處理分佈式一致性
- 使用Redis的有序集合(Sorted Set)將要執行任務的ID和毫秒時間戳ZAdd到有序集合中
- 使用SpringBoot的定時任務,定時1秒去執行消費定任務任務方法
- 消費方法加分佈式鎖,避免重複消息,通過死循環獲取有序集合最小的時間戳與當前時間戳做對比,如果小於則執行,如果大於等線程等待100ms後繼續下一次循環。
-
/** * 獲得分佈式鎖 * * @param redisClientId Redis客戶端ID * @return bool */ public boolean redisDistributedLock(String key, String redisClientId, long timeout, TimeUnit unit) { ValueOperations<String, String> ops = redisTemplate.opsForValue(); if (ops.setIfAbsent(key, redisClientId, timeout, unit)) { return true; } String cacheClientId = ops.get(key); if (cacheClientId.equals(redisClientId)) { redisExpire(key, timeout, unit); return true; } return false; }
/** * 執行定時任務 */ public void runBenchGameDelayTask(BenchDelayTaskType type) { while (true) { Set<ZSetOperations.TypedTuple<String>> typedTuples = benchGameCacheService.benchGameTaskZRange(type); if (typedTuples.size() > 0) { benchGameTaskProcess(type, typedTuples); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); log.error("[runBenchGameDelayTask] type={}, error={}", type.getData(), e); } } }
三、分佈式指定時間執行的定時任務實現方式(三方框架)
-
Quartz集羣解決方案
-
在quartz的集羣解決方案裏有張表scheduler_locks,quartz採用了悲觀鎖的方式對triggers表進行行加鎖,以保證任務同步的正確性。一旦某一個節點上面的線程獲取了該鎖,那麼這個Job就會在這臺機器上被執行,同時這個鎖就會被這臺機器佔用。同時另外一臺機器也會想要觸發這個任務,但是鎖已經被佔用了,就只能等待,直到這個鎖被釋放
-
quartz的分佈式調度策略是以數據庫爲邊界資源的一種異步策略。各個調度器都遵守一個基於數據庫鎖的操作規則從而保證了操作的唯一性
-
原理圖
-
缺點:quartz的分佈式只是解決了高可用的問題,並沒有解決任務分片的問題,還是會有單機處理的極限
-
-
TBSchedule
-
TBSchedule是一款非常優秀的高性能分佈式調度框架,廣泛應用於阿里巴巴、淘寶、支付寶、京東、聚美、汽車之家、國美等很多互聯網企業的流程調度系統。tbschedule在時間調度方面雖然沒有quartz強大,但是它支持分片功能。和quartz不同的是,tbschedule使用ZooKeeper來實現任務調度的高可用和分片
-
原理圖
-
TBSchedule的分佈式機制是通過靈活的Sharding方式實現的,分片的規則由客戶端決定,比如可以按所有數據的ID按10取模分片、按月份分片等等
-
BSchedule會定時掃描當前服務器的數量,重新進行任務分配。TBSchedule不僅提供了服務端的高性能調度服務,還提供了一個scheduleConsole的war包,隨着宿主應用的部署直接部署到服務器,可以通過web的方式對調度的任務、策略進行監控管理,以及實時更新調整
-
-
elastic-job
-
Elastic-Job噹噹開源的分佈式調度解決方案,由兩個相互獨立的子項目Elastic-Job-Lite和Elastic-Job-Cloud組成。Elastic-Job-Lite定位爲輕量級無中心化解決方案,使用jar包的形式提供分佈式任務的協調服務
-
原理圖:
- 特點:
-
分佈式調度協調
- 彈性擴容縮容
- 失效轉移
- 錯過執行作業重觸發
- 作業分片一致性,保證同一分片在分佈式環境中僅一個執行實例
- 自診斷並修復分佈式不穩定造成的問題
- 支持並行調度
- 支持作業生命週期操作
- 豐富的作業類型
- Spring整合以及命名空間提供
- 運維平臺
-
-
-
唯品會開源框架Sature
-
特性如下:
- Time based and language unrestricted job
- Easy job implmentation and web based management
- Parallel subtask(shard) scheduling
- 1-second-level scheduling supported
- Intelligent load based job allocation
- Fail detection & failover support
- Statistical data visualization
- All-around monitoring and easy troubleshooting
- Multi-active cluster deployment support
- Container friendly
- Stand the test of billion times scheduling per day
-
參考博客:
1. [爲什麼你不用Timer](https://www.jianshu.com/p/08181b779706)
2. [Quartz官方文檔](https://www.w3cschool.cn/quartz_doc/)
3. [分佈式定時任務](https://www.jianshu.com/p/e0e7e8494d96)
4. [幾種主流的定時分佈式任務](https://blog.csdn.net/mrleeapple/article/details/87805182)
5. [分佈式開源調度框架TBSchedule原理與應用](https://blog.csdn.net/taosir_zhang/article/details/50728362)
6. [噹噹開源elastic-job使用](https://www.jianshu.com/p/8411504c53a3)
7. [唯品會開源Saturn](https://vipshop.github.io/Saturn/#/zh-cn/3.x/)
8. [PowerJob](https://www.yuque.com/powerjob/guidence/hnbskn)
8. [什麼是分佈式鎖](https://www.jianshu.com/p/a1ebab8ce78a)
9. [一致性Hash原理與實現](https://www.jianshu.com/p/528ce5cd7e8f)