Spring Boot 調度任務在分布式環境下的坑:任務重復執行與一致性保證

前言

在實際業務開發中,調度任務(Scheduled Task)?扮演著重要角色,例如:

  • 定時同步第三方數據;

  • 定時清理過期緩存或日志;

  • 定時發送消息或報告。

Spring Boot 提供了非常方便的?@Scheduled?注解,可以輕松實現定時任務。但在?分布式環境?下(多個服務實例同時運行),調度任務經常會遇到?重復執行任務一致性丟失任務搶占失敗?等問題,輕則數據重復,重則業務異常。

本文將結合實際案例,深入剖析這些坑,并給出?多種解決方案


一、Spring Boot @Scheduled 的局限性

Spring Boot 原生支持定時任務:

@EnableScheduling
@SpringBootApplication
public?class?App?{public?static?void?main(String[] args)?{SpringApplication.run(App.class,?args);}
}@Component
public?class?ScheduledTask?{@Scheduled(cron =?"0 */5 * * * ?")public?void?syncData()?{System.out.println("執行同步任務: "?+ LocalDateTime.now());}
}

👉?問題

  • 單機環境下沒問題;

  • 集群環境中(例如部署了 3 個實例),每個實例都會執行一次,導致任務重復。

📌 示例:如果任務是“清理過期訂單”,那三臺機器同時清理,數據庫會遭遇?重復刪除?或?鎖沖突


二、分布式定時任務常見問題

1. 任務重復執行

  • 多實例同時觸發,導致重復寫庫/發消息。

  • 場景:對賬、數據統計、批量扣款?等敏感業務。

2. 任務不一致

  • 某個實例掛掉,導致任務丟失。

  • 場景:推送消息,部分用戶未收到。

3. 執行時間漂移

  • 默認?@Scheduled?單線程執行,若任務耗時過長,下次調度可能延遲。

  • 場景:大批量任務(幾十萬數據),耗時超出調度周期。


三、解決方案一:數據庫鎖(輕量方案)

最簡單的方式是在任務執行前,借助數據庫表來實現“分布式鎖”。

1. 思路

  • 定義一張?任務鎖表(job_lock),每次執行時先嘗試插入或更新一條記錄;

  • 成功拿到鎖的實例才執行任務,其余實例直接跳過。

2. 表結構

CREATE?TABLE?job_lock (job_name?VARCHAR(64) PRIMARY?KEY,locked_at?TIMESTAMP
);

3. Java 實現

@Component
public?class?ScheduledTask?{@Autowiredprivate?JdbcTemplate jdbcTemplate;@Scheduled(cron =?"0 */5 * * * ?")public?void?syncData()?{int?updated = jdbcTemplate.update("INSERT INTO job_lock(job_name, locked_at) VALUES (?, ?) "?+"ON DUPLICATE KEY UPDATE locked_at = ?","syncData", LocalDateTime.now(), LocalDateTime.now());if?(updated >?0) {// 獲取鎖成功,執行任務doBusiness();}}private?void?doBusiness()?{System.out.println("執行任務 by "?+ InetAddress.getLoopbackAddress());}
}

??優點:簡單易用,適合小型項目。 ???缺點:依賴數據庫,鎖粒度有限,存在性能瓶頸。


四、解決方案二:Redis 分布式鎖

更高效的方式是使用?Redis,利用其?SETNX?原子操作保證只有一個實例能執行。

1. 實現方式

@Component
public?class?RedisScheduledTask?{@Autowiredprivate?StringRedisTemplate redisTemplate;@Scheduled(cron =?"0 */5 * * * ?")public?void?syncData()?{String lockKey =?"job:syncData:lock";String lockValue = UUID.randomUUID().toString();Boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue,?5, TimeUnit.MINUTES);if?(Boolean.TRUE.equals(success)) {try?{doBusiness();}?finally?{redisTemplate.delete(lockKey);}}}private?void?doBusiness()?{System.out.println("執行任務 by "?+ InetAddress.getLoopbackAddress());}
}

??優點:高性能,適合大部分中小型集群。 ???缺點:需保證鎖過期時間合理,否則可能“任務卡死”或“鎖提前過期”。

👉 推薦使用?Redisson 分布式鎖,更健壯。


五、解決方案三:Quartz 分布式調度

Quartz?是 Java 領域成熟的調度框架,支持?集群模式

1. 原理

  • 所有任務元數據存放在數據庫中;

  • 多實例競爭任務執行權,Quartz 內部保證只會有一個實例執行。

2. 配置示例

spring:quartz:job-store-type:?jdbcjdbc:initialize-schema:?alwaysproperties:org.quartz.jobStore.isClustered:?true

3. 使用

@Component
public?class?QuartzJob?implements?Job?{@Overridepublic?void?execute(JobExecutionContext context)?{System.out.println("Quartz任務執行: "?+ LocalDateTime.now());}
}

??優點:功能強大,支持任務持久化、分布式、失敗重試。 ???缺點:依賴數據庫,配置復雜,適合?企業級調度場景


六、解決方案四:分布式任務調度平臺(XXL-Job / Elastic-Job)

如果任務量大、分布式調度需求強烈,推薦使用專門的調度平臺:

1. XXL-Job

  • 提供管理控制臺,可動態配置任務;

  • 支持分片、失敗重試、報警。

2. Elastic-Job

  • 基于 Zookeeper/Etcd,支持任務分片和彈性伸縮;

  • 適合大規模集群。

3. 對比

框架

特點

適用場景

Quartz

成熟、穩定、基于 DB

企業系統、需要持久化任務

XXL-Job

輕量、帶 UI、動態配置

互聯網項目、分布式調度

Elastic-Job

分片、彈性、ZooKeeper 支持

大規模任務調度


七、如何保證任務一致性?

  1. 冪等性設計

    • 即使任務重復執行,也不會造成數據錯誤。

    • 例如:更新狀態前先檢查,寫庫時加唯一索引。

  2. 分布式鎖

    • 保證只有一個實例執行任務。

  3. 任務分片

    • 多個實例分工合作,提高吞吐量。

  4. 日志與監控

    • 記錄任務執行情況,方便排查問題。


八、最佳實踐總結

  • 小型系統(單機/簡單集群):@Scheduled + Redis 鎖

  • 中型系統(需要持久化任務):Quartz 集群

  • 大型系統(任務多且復雜):XXL-Job / Elastic-Job

👉 核心原則:

  • 保證冪等性(防止重復執行影響業務);

  • 保證可觀測性(日志、監控、報警);

  • 根據業務場景選擇合適的調度框架


結語

Spring Boot 自帶的?@Scheduled?適合小型項目,但在?分布式環境?下會踩坑:任務重復執行、任務丟失、一致性無法保證。

針對這些問題,可以采用:

  • 數據庫鎖 / Redis 鎖?→ 輕量方案;

  • Quartz 集群?→ 穩定持久化方案;

  • XXL-Job / Elastic-Job?→ 企業級分布式任務平臺。

只有根據業務場景選擇合適的方案,并做好?冪等性 + 分布式鎖 + 日志監控,才能讓調度任務在復雜環境下穩定可靠。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/97917.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/97917.shtml
英文地址,請注明出處:http://en.pswp.cn/web/97917.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

剖析ReAct:當大模型學會“邊想邊做”,智能體的進化之路

你是否曾驚嘆于大語言模型(LLM)強大的推理能力,卻又對其“紙上談兵”、無法真正與世界交互而感到遺憾?你是否好奇,如何讓AI不僅能“說”,更能“做”,并且在做的過程中不斷思考和調整&#xff1f…

小型無人機傳感器仿真模型MATLAB實現方案

一、系統架構設計 無人機傳感器仿真模型需集成多物理場建模與數據融合模塊,典型架構包含: 動力學模型:六自由度剛體運動方程傳感器模型:IMU/GNSS/視覺/氣壓計數學建模數據融合層:卡爾曼濾波/EKF算法實現環境交互模塊&a…

hadoop集群

ssh-keygen -t rsassh-copyid 用戶名遠程服務器地址start-dfs.sh chown [選項] 新所有者[:新所屬組] 目標文件/目錄常用選項:-R:遞歸修改目錄下所有文件和子目錄的所有者(處理目錄時常用)-v:顯示修改過程的詳細信息-c&…

大模型入門實踐指南

大模型入門教程:從概念到實踐 大模型(Large Language Model, LLM)是當前人工智能領域的核心技術,其本質是通過大規模數據訓練、具備復雜語言理解與生成能力的深度學習模型。本教程將從基礎概念出發,帶你理解大模型的核心邏輯,并通過可直接跑通的代碼示例,快速上手大模型…

貓頭虎開源AI分享:一款CSV to Chat AI工具,上傳CSV文件提問,它可以即時返回統計結果和可視化圖表

貓頭虎開源AI分享:一款CSV to Chat AI工具,上傳CSV文件提問,它可以即時返回統計結果和可視化圖表 摘要 本文將詳細介紹一款開源工具——CSV to Chat AI,它允許用戶上傳CSV文件并通過自然語言提問,系統會即時返回統計…

洛谷P9468 [EGOI 2023] Candy / 糖果題解

[EGOI 2023] Candy / 糖果 思路 NNN 這么小基本就是瞎打的 DP 了。 設 dpi,jdp_{i,j}dpi,j? 為操作 jjj 次后前 iii 項的和最大是多少。 考慮轉移,我們可以枚舉 iii 并考慮將其移動到 ppp 位置,總共操作 kkk 次,那么就有 dpp,kmin?(dpp,…

AI智能體(Agent)大模型入門【3】--基于Chailit客服端實現頁面AI對話

目錄 前言 安裝chailint 創建中文語言環境 創建chailint頁面客戶端 前言 本篇章將會基chailit框架實現頁面進行AI對話。 若沒有自己的本地模型對話,需要查看專欄內的文章,或者點擊鏈接進行學習部署 AI智能體(Agent)大模型入…

【高并發內存池——項目】定長內存池——開胃小菜

提示:高并發內存池完整項目代碼,在主頁專欄項目中 文章目錄 提示:高并發內存池完整項目代碼,在主頁專欄項目中 先設計一個定長的內存池 一、為什么需要定長內存池? 🏢 傳統內存分配的痛點 🏭 內…

6-獲取磁盤分區信息

觀察文件 獲取server端電腦里面存在哪些盤符 int MakeDriveInfo() { //1>A 2>B &#xff08;原本屬于軟盤的 &#xff09;3>C ... 26>Zstd::string result;for (int i 1; i < 26; i) { //讓其循環if (_chdrive(i) 0) //改變當前的驅動,_chdrive函數(c和c中)應…

每天認識一個電子器件之LED燈

LED選型核心參數一覽表參數類別關鍵參數說明 & 為什么重要基本電氣參數正向電壓 (Vf)LED正常發光時兩端的電壓降。必須匹配您的電路電壓。紅/黃光約1.8-2.2V&#xff0c;藍/綠/白光約2.8-3.6V。正向電流 (If)LED正常發光時所需的電流。決定了LED的亮度&#xff0c;必須用電…

Spring Boot 集成 Flowable 7.1.0 完整教程

一、引言 在企業級應用開發中&#xff0c;工作流管理是不可或缺的一部分。從簡單的請假審批到復雜的業務流程&#xff0c;工作流引擎能夠顯著提升系統的靈活性和可維護性。??Flowable?? 作為一個輕量級、基于 Java 的開源工作流引擎&#xff0c;完美支持 ??BPMN 2.0??…

uniapp離線打包安卓apk詳細教程,從HbuilderX新建項目到Android Studio詳細配置(一)

目錄 一、基礎離線打包&#xff0c;無引入模塊&#xff0c;無原生插件 1. HbuilderX新建項目&#xff0c;開發者后臺申請證書和離線key 2.HbuilderX生成本地包 二、Android Studio配置 1.下載離線SDK&#xff0c;解壓&#xff0c;SDK版本需要和HbuilderX 版本一致&#xf…

藍牙鼠標頻繁卡頓?一招解決 Win10/11 的 USB 省電機制干擾問題

藍牙鼠標頻繁卡頓&#xff1f;一招解決 Win10/11 的 USB 省電機制干擾問題 問題背景 在使用藍牙鼠標時&#xff0c;很多用戶會遇到以下問題&#xff1a; 鼠標移動卡頓、延遲明顯偶爾斷連&#xff0c;需重新配對尤其在筆記本合蓋或待機后恢復時更明顯 這些問題在 Windows 10/11 …

領碼方案|Spring Boot 異步請求深度剖析:從原理到 AI 驅動的吞吐量優化

摘要 本文以“領碼方案”為核心&#xff0c;深入剖析 Spring Boot 異步請求的底層原理、線程模型、三種常用實現方式&#xff08;Callable、WebAsyncTask、DeferredResult&#xff09;的運行機制與性能特征&#xff0c;并結合 AI 驅動的自適應線程池調優、云原生架構下的彈性伸…

C++基礎(13)——list類的模擬實現

目錄 一、接口函數和類總覽 二、節點結構體的實現 構造函數 三、迭代器結構體的實現 迭代器模版參數 構造函數 重載運算符 重載--運算符 重載運算符 重載*運算符 重載->運算符 四、list的模擬實現 默認成員函數 構造函數 拷貝構造函數 賦值運算符重載函數 …

從 APP 界面設計到用戶體驗優化:如何讓你的應用脫穎而出?

作為一個經驗豐富的設計師&#xff0c;在產品優化方面我踩過不少坑&#xff0c;也見過很多團隊在界面設計和用戶體驗上的誤區。APP 的外觀決定了用戶的第一印象&#xff0c;但能不能留住用戶、讓他們愿意持續使用&#xff0c;最終還是看體驗。今天就結合自己的經驗&#xff0c;…

Kafka如何配置生產者攔截器和消費者攔截器

Kafka 的生產者攔截器和消費者攔截器允許你在消息發送前后以及消息消費前后嵌入自定義邏輯&#xff0c;用于實現監控、審計、消息修改等功能。本文我們就用一個最常見的傳遞TraceId的案例來說明下這兩類攔截器如何來使用。 生產者發送攔截器 生產者攔截器需要實現 org.apache.k…

vue表單彈窗最大化無法渲染復雜組件內容

背景&#xff1a;最大化后選然后復雜組件內容丟失&#xff0c;如下拉框、圖片上傳組件修復方案&#xff1a;使用深拷貝核心代碼this.maximizeDialog {visible: true,title: 患者申請 - 最大化查看,formModel: JSON.parse(JSON.stringify(this.formModel || [])),formLogic: JS…

經典俄羅斯方塊游戲 | 安卓三模式暢玩,暫時無廣告!

大家好&#xff0c;今天想跟大家分享一款安卓版的俄羅斯方塊游戲。適合無聊的時候玩玩&#xff0c;換換腦子&#xff0c;這款游戲太經典。80、90都玩過這個游戲。之前我也給大家推薦過一些離線小游戲&#xff0c;但有些用著用著就開始出現彈窗廣告&#xff0c;這就有點煩&#…

今天開始學習新內容“服務集群與自動化”--crond服務、--syslog服務以及DHCP協議

一.crond簡介1、基本介紹crond是linux下用來周期性的執行某種任務或等待處理某些事件的一個守護進程&#xff0c;與windows下的計劃任務類似&#xff0c;當安裝完成操作系統后&#xff0c;默認會安裝此服務工具&#xff0c;并且會自動啟動crond進程&#xff0c;crond進程每分鐘…