SpringBoot集成ShedLock實現(xiàn)分布式定時任務
1.什么是ShedLock?
ShedLock 是一個 Java 庫,通常用于分布式系統(tǒng)中,確保定時任務(Scheduled Tasks)在集群環(huán)境下只被某一個實例執(zhí)行一次。它通過在共享資源(例如數(shù)據(jù)庫或分布式緩存)中添加鎖的方式,避免多個實例同時執(zhí)行相同的任務
ShedLock 的工作原理
- 分布式鎖:
- 在任務開始時,ShedLock 會嘗試在數(shù)據(jù)庫(或其他存儲)中創(chuàng)建一個鎖。
- 如果某個實例成功獲取鎖,則只有它能執(zhí)行該任務。
- 鎖的生命周期:
- 鎖會有一個明確的過期時間(鎖的持有時間,
lockAtLeastFor
和lockAtMostFor
參數(shù)配置)。 - 鎖過期后,即使任務異常終止,其他實例也可以重新獲取鎖。
- 鎖會有一個明確的過期時間(鎖的持有時間,
- 支持的存儲:
- 支持多種鎖存儲,包括數(shù)據(jù)庫(如 MySQL、PostgreSQL)、Redis、MongoDB 等。
應用場景
1. 分布式定時任務控制
- 在分布式環(huán)境中,多個實例會同時調度定時任務。如果沒有控制,可能導致任務重復執(zhí)行。ShedLock 確保只有一個實例能運行任務。
- 例如:
- 生成日報表的定時任務。
- 清理過期數(shù)據(jù)的批處理任務。
2. 避免重復任務執(zhí)行
- 即使在單實例環(huán)境中,也可以使用 ShedLock 避免因意外重啟或配置錯誤導致同一任務被多次觸發(fā)。
3. 事件驅動任務的冪等性
- 當某些任務需要對同一事件觸發(fā)處理時,使用 ShedLock 可以確保一個事件只被處理一次。
4. 任務重試機制
- 如果任務需要重試(例如在發(fā)生錯誤時),ShedLock 能避免多個實例同時重試相同任務。
2.代碼工程
實驗目的
使用ShedLock 來確保在分布式環(huán)境中只有一個實例能運行任務
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 * * * ?")
- 定義定時任務的調度時間。
- 表達式含義:任務每分鐘的整點觸發(fā),例如 12:00、12:01、12:02。
- 注意:多個實例(分布式環(huán)境)都會在同一時間調度到此任務,但通過 ShedLock 確保只有一個實例能真正執(zhí)行。
@SchedulerLock
- 使用 ShedLock 來管理分布式鎖。
name = "scheduledTaskName"
:- 定義鎖的唯一標識。共享存儲(如數(shù)據(jù)庫或 Redis)中會記錄此鎖的狀態(tài)。
lockAtMostFor = "PT10M"
:- 鎖的最長持有時間為 10分鐘。
- 如果任務運行超出 10 分鐘,即使沒有主動釋放鎖,也會自動過期,其他實例可以繼續(xù)獲取鎖。
lockAtLeastFor = "PT1M"
:- 鎖的最短持有時間為 1分鐘。
- 即使任務提前完成,鎖仍會持有至少 1 分鐘,防止其他實例快速重復執(zhí)行任務。
- 任務邏輯
System.out.println("Executing scheduled task");
是任務的業(yè)務邏輯。- 此邏輯只會在獲得鎖的實例上執(zhí)行。
配置文件
node1節(jié)點
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é)點
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.測試
啟動node1節(jié)點
java -jar myapp.jar --spring.profiles.active=node1
啟動node2節(jié)點
java -jar myapp.jar --spring.profiles.active=node2
通過控制臺觀察日志,可以發(fā)現(xiàn),2個實例交替獲取到鎖執(zhí)行,而不是同一時刻一起執(zhí)行
4.注意事項
- 任務時間控制: 確保任務的實際執(zhí)行時間小于
lockAtMostFor
,否則任務可能被其他實例重復執(zhí)行。 - 冪等性: 任務邏輯應盡量設計為冪等的(重復執(zhí)行不會產生副作用),以應對鎖機制的潛在異常情況。
- 存儲配置: 確保使用高可用的鎖存儲(如數(shù)據(jù)庫或 Redis),否則鎖機制可能失效。
以上就是SpringBoot集成ShedLock實現(xiàn)分布式定時任務的詳細內容,更多關于SpringBoot ShedLock定時任務的資料請關注腳本之家其它相關文章!
相關文章
idea中使用SonarLint進行代碼規(guī)范檢測及使用方法
這篇文章主要介紹了idea中使用SonarLint進行代碼規(guī)范檢測,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08在Spring Boot中實現(xiàn)文件上傳與管理的操作
在 Spring Boot 中實現(xiàn)文件上傳與管理非常簡單,通過配置文件上傳、創(chuàng)建文件上傳、下載、列表和刪除接口,我們可以輕松地處理文件操作,結合前端頁面,可以提供一個完整的文件管理系統(tǒng),這篇文章主要介紹了在Spring Boot中實現(xiàn)文件上傳與管理,需要的朋友可以參考下2024-07-07vue+springboot項目上傳部署tomcat的方法實現(xiàn)
本文主要介紹了vue+springboot項目上傳部署tomcat的方法實現(xiàn),包括環(huán)境準備、配置調整以及部署步驟,文中通過圖文及示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-01-01