SpringBoot集成ShedLock實(shí)現(xiàn)分布式定時(shí)任務(wù)的示例代碼
1、什么是ShedLock?
ShedLock 是一個(gè) Java 庫(kù),通常用于分布式系統(tǒng)中,確保定時(shí)任務(wù)(Scheduled Tasks)在集群環(huán)境下只被某一個(gè)實(shí)例執(zhí)行一次。它通過在共享資源(例如數(shù)據(jù)庫(kù)或分布式緩存)中添加鎖的方式,避免多個(gè)實(shí)例同時(shí)執(zhí)行相同的任務(wù)
ShedLock 的工作原理
1.分布式鎖:
在任務(wù)開始時(shí),ShedLock 會(huì)嘗試在數(shù)據(jù)庫(kù)(或其他存儲(chǔ))中創(chuàng)建一個(gè)鎖。
如果某個(gè)實(shí)例成功獲取鎖,則只有它能執(zhí)行該任務(wù)。
2.鎖的生命周期:
鎖會(huì)有一個(gè)明確的過期時(shí)間(鎖的持有時(shí)間,lockAtLeastFor 和 lockAtMostFor 參數(shù)配置)。
鎖過期后,即使任務(wù)異常終止,其他實(shí)例也可以重新獲取鎖。
3.支持的存儲(chǔ):
支持多種鎖存儲(chǔ),包括數(shù)據(jù)庫(kù)(如 MySQL、PostgreSQL)、Redis、MongoDB 等。
應(yīng)用場(chǎng)景
1、分布式定時(shí)任務(wù)控制
在分布式環(huán)境中,多個(gè)實(shí)例會(huì)同時(shí)調(diào)度定時(shí)任務(wù)。如果沒有控制,可能導(dǎo)致任務(wù)重復(fù)執(zhí)行。ShedLock 確保只有一個(gè)實(shí)例能運(yùn)行任務(wù)。
例如:
生成日?qǐng)?bào)表的定時(shí)任務(wù)。
清理過期數(shù)據(jù)的批處理任務(wù)。
2、避免重復(fù)任務(wù)執(zhí)行
即使在單實(shí)例環(huán)境中,也可以使用 ShedLock 避免因意外重啟或配置錯(cuò)誤導(dǎo)致同一任務(wù)被多次觸發(fā)。
3、事件驅(qū)動(dòng)任務(wù)的冪等性
當(dāng)某些任務(wù)需要對(duì)同一事件觸發(fā)處理時(shí),使用 ShedLock 可以確保一個(gè)事件只被處理一次。
4、任務(wù)重試機(jī)制
如果任務(wù)需要重試(例如在發(fā)生錯(cuò)誤時(shí)),ShedLock 能避免多個(gè)實(shí)例同時(shí)重試相同任務(wù)。
2、代碼工程
實(shí)驗(yàn)?zāi)康?br />使用ShedLock 來確保在分布式環(huán)境中只有一個(gè)實(shí)例能運(yùn)行任務(wù)
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.1</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>shedlock</artifactId> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>5.5.0</version> </dependency> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jdbc-template</artifactId> <version>5.5.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> </dependencies> </project>
config
package com.demo.config; import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; @Configuration public class ShedLockConfig { @Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider( JdbcTemplateLockProvider.Configuration.builder() .withJdbcTemplate(new JdbcTemplate(dataSource)) .usingDbTime() // Works with PostgreSQL, MySQL, MariaDb, MS SQL, Oracle, HSQL, H2, DB2, and others .build() ); } }
cron
package com.demo.cron; import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; @Configuration @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "PT30S") public class SchedulerConfig { @Scheduled(cron = "0 0/1 * * * ?") @SchedulerLock(name = "scheduledTaskName", lockAtMostFor = "PT10M", lockAtLeastFor = "PT1M") public void scheduledTask() { // some logic code System.out.println("Executing scheduled task"); } }
@Scheduled(cron = “0 0/1 * * * ?”)
1、定義定時(shí)任務(wù)的調(diào)度時(shí)間。
2、表達(dá)式含義:任務(wù)每分鐘的整點(diǎn)觸發(fā),例如 12:00、12:01、12:02。
3、注意:多個(gè)實(shí)例(分布式環(huán)境)都會(huì)在同一時(shí)間調(diào)度到此任務(wù),但通過 ShedLock 確保只有一個(gè)實(shí)例能真正執(zhí)行。
@SchedulerLock
1、鎖的最短持有時(shí)間為 1分鐘。
2、即使任務(wù)提前完成,鎖仍會(huì)持有至少 1 分鐘,防止其他實(shí)例快速重復(fù)執(zhí)行任務(wù)。
3、鎖的最長(zhǎng)持有時(shí)間為 10分鐘。
4、如果任務(wù)運(yùn)行超出 10 分鐘,即使沒有主動(dòng)釋放鎖,也會(huì)自動(dòng)過期,其他實(shí)例可以繼續(xù)獲取鎖。
5、定義鎖的唯一標(biāo)識(shí)。共享存儲(chǔ)(如數(shù)據(jù)庫(kù)或 Redis)中會(huì)記錄此鎖的狀態(tài)。
6、使用 ShedLock 來管理分布式鎖。
7、name = “scheduledTaskName”:
8、lockAtMostFor = “PT10M”:
9、lockAtLeastFor = “PT1M”:
任務(wù)邏輯
1、System.out.println(“Executing scheduled task”); 是任務(wù)的業(yè)務(wù)邏輯。
2、此邏輯只會(huì)在獲得鎖的實(shí)例上執(zhí)行。
配置文件
node1節(jié)點(diǎn)
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver server.port=8081
node2節(jié)點(diǎn)
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver server.port=8082
3、測(cè)試
1、啟動(dòng)node1節(jié)點(diǎn)
java -jar myapp.jar --spring.profiles.active=node1
2、啟動(dòng)node2節(jié)點(diǎn)
java -jar myapp.jar --spring.profiles.active=node2
通過控制臺(tái)觀察日志,可以發(fā)現(xiàn),2個(gè)實(shí)例交替獲取到鎖執(zhí)行,而不是同一時(shí)刻一起執(zhí)行
4、注意事項(xiàng)
- 任務(wù)時(shí)間控制: 確保任務(wù)的實(shí)際執(zhí)行時(shí)間小于 lockAtMostFor,否則任務(wù)可能被其他實(shí)例重復(fù)執(zhí)行。
- 冪等性: 任務(wù)邏輯應(yīng)盡量設(shè)計(jì)為冪等的(重復(fù)執(zhí)行不會(huì)產(chǎn)生副作用),以應(yīng)對(duì)鎖機(jī)制的潛在異常情況。
- 存儲(chǔ)配置: 確保使用高可用的鎖存儲(chǔ)(如數(shù)據(jù)庫(kù)或 Redis),否則鎖機(jī)制可能失效。
以上就是SpringBoot集成ShedLock實(shí)現(xiàn)分布式定時(shí)任務(wù)的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot ShedLock分布式定時(shí)任務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot項(xiàng)目使用@Scheduled注解實(shí)現(xiàn)定時(shí)任務(wù)的方法
- SpringBoot整合ShedLock解決定時(shí)任務(wù)防止重復(fù)執(zhí)行的問題
- SpringBoot項(xiàng)目如何使用多線程執(zhí)行定時(shí)任務(wù)
- SpringBoot最新定時(shí)任務(wù)的7種實(shí)現(xiàn)方案
- springboot定時(shí)任務(wù)不起作用問題及解決
- 基于SpringBoot實(shí)現(xiàn)輕量級(jí)的動(dòng)態(tài)定時(shí)任務(wù)調(diào)度的方法
- SpringBoot最簡(jiǎn)單的定時(shí)任務(wù)@Scheduler的使用及解讀
相關(guān)文章
java實(shí)現(xiàn)在普通類中注入service或mapper
這篇文章主要介紹了java實(shí)現(xiàn)在普通類中注入service或mapper的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07java?集合工具類Collections及Comparable和Comparator排序詳解
這篇文章主要介紹了java集合工具類Collections及Comparable和Comparator排序詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-06-06Spring?Boot?中正確地在異步線程中使用?HttpServletRequest的方法
文章討論了在Spring?Boot中如何在異步線程中正確使用HttpServletRequest的問題,介紹了Tomcat的請(qǐng)求對(duì)象復(fù)用機(jī)制及其對(duì)異步線程的影響,并解釋了AsyncContext的作用與局限性,感興趣的朋友一起看看吧2025-03-03Java利用poi實(shí)現(xiàn)word表格轉(zhuǎn)excel
這篇文章主要為大家詳細(xì)介紹了Java如何利用poi實(shí)現(xiàn)word表格轉(zhuǎn)excel,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-03-03Java 中HashCode作用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java 中HashCode作用以及hashcode對(duì)于一個(gè)對(duì)象的重要性,對(duì)java中hashcode的作用相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2017-05-05Java BigDecimal類的使用和注意事項(xiàng)
這篇文章主要講解Java中BigDecimal類的用法,并簡(jiǎn)單介紹一些注意事項(xiàng),希望能給大家做一個(gè)參考。2016-06-06SpringBoot實(shí)戰(zhàn)之實(shí)現(xiàn)結(jié)果的優(yōu)雅響應(yīng)案例詳解
這篇文章主要介紹了SpringBoot實(shí)戰(zhàn)之實(shí)現(xiàn)結(jié)果的優(yōu)雅響應(yīng)案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09SpringMVC使用hibernate-validator進(jìn)行參數(shù)校驗(yàn)最佳實(shí)踐記錄
這篇文章主要介紹了SpringMVC使用hibernate-validator進(jìn)行參數(shù)校驗(yàn)最佳實(shí)踐,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05