SpringBoot集成ShedLock实现分布式定时任务的示例代码
1、什么是ShedLock?
ShedLock 是一个 Java 库,通常用于分布式系统中,确保定时任务(Scheduled Tasks)在集群环境下只被某一个实例执行一次。它通过在共享资源(例如数据库或分布式缓存)中添加锁的方式,避免多个实例同时执行相同的任务
ShedLock 的工作原理
1.分布式锁:
在任务开始时,ShedLock 会尝试在数据库(或其他存储)中创建一个锁。
如果某个实例成功获取锁,则只有它能执行该任务。
2.锁的生命周期:
锁会有一个明确的过期时间(锁的持有时间,lockAtLeastFor 和 lockAtMostFor 参数配置)。
锁过期后,即使任务异常终止,其他实例也可以重新获取锁。
3.支持的存储:
支持多种锁存储,包括数据库(如 MySQL、PostgreSQL)、Redis、MongoDB 等。
应用场景
1、分布式定时任务控制
在分布式环境中,多个实例会同时调度定时任务。如果没有控制,可能导致任务重复执行。ShedLock 确保只有一个实例能运行任务。
例如:
生成日报表的定时任务。
清理过期数据的批处理任务。
2、避免重复任务执行
即使在单实例环境中,也可以使用 ShedLock 避免因意外重启或配置错误导致同一任务被多次触发。
3、事件驱动任务的幂等性
当某些任务需要对同一事件触发处理时,使用 ShedLock 可以确保一个事件只被处理一次。
4、任务重试机制
如果任务需要重试(例如在发生错误时),ShedLock 能避免多个实例同时重试相同任务。
2、代码工程
实验目的
使用ShedLock 来确保在分布式环境中只有一个实例能运行任务
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、定义定时任务的调度时间。
2、表达式含义:任务每分钟的整点触发,例如 12:00、12:01、12:02。
3、注意:多个实例(分布式环境)都会在同一时间调度到此任务,但通过 ShedLock 确保只有一个实例能真正执行。
@SchedulerLock
1、锁的最短持有时间为 1分钟。
2、即使任务提前完成,锁仍会持有至少 1 分钟,防止其他实例快速重复执行任务。
3、锁的最长持有时间为 10分钟。
4、如果任务运行超出 10 分钟,即使没有主动释放锁,也会自动过期,其他实例可以继续获取锁。
5、定义锁的唯一标识。共享存储(如数据库或 Redis)中会记录此锁的状态。
6、使用 ShedLock 来管理分布式锁。
7、name = “scheduledTaskName”:
8、lockAtMostFor = “PT10M”:
9、lockAtLeastFor = “PT1M”:
任务逻辑
1、System.out.println(“Executing scheduled task”); 是任务的业务逻辑。
2、此逻辑只会在获得锁的实例上执行。
配置文件
node1节点
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节点
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、测试
1、启动node1节点
java -jar myapp.jar --spring.profiles.active=node1
2、启动node2节点
java -jar myapp.jar --spring.profiles.active=node2
通过控制台观察日志,可以发现,2个实例交替获取到锁执行,而不是同一时刻一起执行
4、注意事项
- 任务时间控制: 确保任务的实际执行时间小于 lockAtMostFor,否则任务可能被其他实例重复执行。
- 幂等性: 任务逻辑应尽量设计为幂等的(重复执行不会产生副作用),以应对锁机制的潜在异常情况。
- 存储配置: 确保使用高可用的锁存储(如数据库或 Redis),否则锁机制可能失效。
以上就是SpringBoot集成ShedLock实现分布式定时任务的示例代码的详细内容,更多关于SpringBoot ShedLock分布式定时任务的资料请关注脚本之家其它相关文章!
相关文章
SpringCloud微服务开发基于RocketMQ实现分布式事务管理详解
分布式事务是在微服务开发中经常会遇到的一个问题,之前的文章中我们已经实现了利用Seata来实现强一致性事务,其实还有一种广为人知的方案就是利用消息队列来实现分布式事务,保证数据的最终一致性,也就是我们常说的柔性事务2022-09-09Java使用Runnable和Callable实现多线程的区别详解
这篇文章主要为大家详细介绍了Java使用Runnable和Callable实现多线程的区别之处,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下2022-07-07SpringMVC参数的传递之如何接收List数组类型的数据
这篇文章主要介绍了SpringMVC参数的传递之如何接收List数组类型的数据,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-10-10
最新评论