分佈式定時任務原理(附解決方案)
一、單機指定時間執行定時任務實現方式
1.Timer 運行機制
2.ScheduledThreadPoolExecutor 的運行機制
1. 原理圖
2.Leader/Follower 模式
3.Timer 和 ScheduledThreadPoolExucutor 區別
-
Timer 是基於絕對時間,ScheduledThreadPoolExucutor 基於相對時間
-
Timer 是單線程,ScheduledThreadPoolExucutor 是多線程
-
Timer 運行發生異常,整個 TimerThread 崩潰,而 ScheduledThreadPoolExucutor 對異常進行捕獲
4. 自行實現指定時間執行的定時任務
-
建立數據庫定時任務表,用戶存入要執行的定時任務,業務 ID
-
定義 Producer 類,用於生產指定定時任務,往延遲隊列裏寫入數據,指定的毫秒時間戳
-
定義 Consumer 接口,自身業務可以通過實現 Consumer 接口消費隊列中的數據
-
定義 SpringBoot 自啓動方法,死循環從延遲隊列中取最小時間戳數據,與當前時間進行對比如果小於則開始執行,休眠 100ms 繼續下一次循環
5.Quartz 實現
參考文檔:https://www.w3cschool.cn/quartz_doc/quartz_doc-2put2clm.html
二、分佈式指定時間執行的定時任務實現方式(自行 Redis 實現)
1. 流程設計分析
-
因爲是應用是分佈式部署,所以需要考慮分佈式鎖處理分佈式一致性
-
使用 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);
}
}
}
三、分佈式指定時間執行的定時任務實現方式(三方框架)
1.Quartz 集羣解決方案
在 quartz 的集羣解決方案裏有張表 scheduler_locks,quartz 採用了悲觀鎖的方式對 triggers 表進行行加鎖,以保證任務同步的正確性。一旦某一個節點上面的線程獲取了該鎖,那麼這個 Job 就會在這臺機器上被執行,同時這個鎖就會被這臺機器佔用。同時另外一臺機器也會想要觸發這個任務,但是鎖已經被佔用了,就只能等待,直到這個鎖被釋放
quartz 的分佈式調度策略是以數據庫爲邊界資源的一種異步策略。各個調度器都遵守一個基於數據庫鎖的操作規則從而保證了操作的唯一性
原理圖
缺點:quartz 的分佈式只是解決了高可用的問題,並沒有解決任務分片的問題,還是會有單機處理的極限
2.TBSchedule
TBSchedule 是一款非常優秀的高性能分佈式調度框架,廣泛應用於阿里巴巴、淘寶、支付寶、京東、聚美、汽車之家、國美等很多互聯網企業的流程調度系統。tbschedule 在時間調度方面雖然沒有 quartz 強大,但是它支持分片功能。和 quartz 不同的是,tbschedule 使用 ZooKeeper 來實現任務調度的高可用和分片
原理圖
TBSchedule 的分佈式機制是通過靈活的 Sharding 方式實現的,分片的規則由客戶端決定,比如可以按所有數據的 ID 按 10 取模分片、按月份分片等等
BSchedule 會定時掃描當前服務器的數量,重新進行任務分配。TBSchedule 不僅提供了服務端的高性能調度服務,還提供了一個 scheduleConsole 的 war 包,隨着宿主應用的部署直接部署到服務器,可以通過 web 的方式對調度的任務、策略進行監控管理,以及實時更新調整
3.elastic-job
Elastic-Job 噹噹開源的分佈式調度解決方案,由兩個相互獨立的子項目 Elastic-Job-Lite 和 Elastic-Job-Cloud 組成。Elastic-Job-Lite 定位爲輕量級無中心化解決方案,使用 jar 包的形式提供分佈式任務的協調服務
原理圖:
特點:
-
分佈式調度協調
-
彈性擴容縮容
-
失效轉移
-
錯過執行作業重觸發
-
作業分片一致性,保證同一分片在分佈式環境中僅一個執行實例
-
自診斷並修復分佈式不穩定造成的問題
-
支持並行調度
-
支持作業生命週期操作
-
豐富的作業類型
-
Spring 整合以及命名空間提供
-
運維平臺
4. 唯品會開源框架 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
_感謝閱讀,希望對你有所幫助 :) _
來源:blog.csdn.net/luomao2012/article/details/107035609
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Zi0zZp1SevRvWbUwsX-iTQ