springBoot框架分布式部署定时任务重复执行之解决方案 ゞ 浴缸里的玫瑰 2021-09-23 12:32 705阅读 0赞 在集群模式部署服务端时,会出现所有的定时任务在各自的节点处均会执行一遍,这显然不符合实际的开发场景,针对这种问题,本文给出一种springboot集成shedlock的解决方案 第一步:引入相关包; ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] <!-- 负载均衡定时任务执行一次 --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jdbc-template</artifactId> <version>2.2.1</version> </dependency> ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] 注意:因为本公司的项目持久化采用的mysql数据库,所以引入的是JDBC数据库进行协调 ![format_png][] ShedLock还可以使用Mongo,Redis,Hazelcast,ZooKeeper等外部存储进行协调,例如使用redis则引入下面的包(只尝试过jdbc方式): ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-redis-spring</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] 针对不同的协调方式,相关的配置信息可参考https://www.jianshu.com/p/9c6791b617a7 第二步:向数据库中插入表shedlock; ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] CREATE TABLE shedlock( NAME VARCHAR(64), lock\_until TIMESTAMP(3) NULL, locked\_at TIMESTAMP(3) NULL, locked\_by VARCHAR(255), PRIMARY KEY (NAME) ) ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] 第三步:在application.properties中添加数据库配置信息 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true spring.datasource.username=root1 spring.datasource.password=root1 第四步:添加配置类 ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; import net.javacrumbs.shedlock.spring.ScheduledLockConfiguration; import net.javacrumbs.shedlock.spring.ScheduledLockConfigurationBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.annotation.EnableScheduling; import javax.sql.DataSource; import java.time.Duration; @Configuration @EnableScheduling public class ShedlockConfig { @Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider(dataSource); } // @Bean // public TaskScheduler taskScheduler(){ // return new MySpecialTaskScheduler(); // } @Bean public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) { return ScheduledLockConfigurationBuilder .withLockProvider(lockProvider) .withPoolSize(10) .withDefaultLockAtMostFor(Duration.ofMinutes(10)) .build(); } } ![复制代码][aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg] 第五步:在启动类上添加启动注解,否则SchedulerLock不会生效 @EnableSchedulerLock(defaultLockAtMostFor = "PT50S") 第六步:添加@SchedulerLock到定时器业务方法入口 private static final int TWENTY_NINE_MIN = 29 * 60 * 1000; @Scheduled(cron = "0 */30 * * * ?") @SchedulerLock(name = "scheduledTask", lockAtMostFor = TWENTY_NINE_MIN, lockAtLeastFor = TWENTY_NINE_MIN) public void scheduledTask() { // System.out.println(new Date() + "scheduledTask执行1次"); } 参数解释: name属性:锁名称,必须指定,每次只能执行一个具有相同名字的任务,锁名称应该是全局唯一的; lockAtMostFor属性:设置锁的最大持有时间,为了解决如果持有锁的节点挂了,无法释放锁,其他节点无法进行下一次任务; lockAtMostForString属性:成功执行任务的节点所能拥有的独占锁的最长时间的字符串表达,例如“PT14M”表示为14分钟 lockAtLeastFor属性:指定保留锁的最短时间。主要目的是在任务非常短的且节点之间存在时钟差异的情况下防止多个节点执行。这个属性是锁的持有时间。设置了多少就一定会持有多长时间,再此期间,下一次任务执行时,其他节点包括它本身是不会执行任务的 lockAtLeastForString属性:成功执行任务的节点所能拥有的独占锁的最短时间的字符串表达,例如“PT14M”表示为14分钟 [aHR0cHM6Ly9jb21tb24uY25ibG9ncy5jb20vaW1hZ2VzL2NvcHljb2RlLmdpZg]: /images/20210923/73d0ebc1ccde4a60bf42be65b6d92610.png [format_png]: /images/20210923/acb30adac90e4d2ca1061170c1639c26.png
还没有评论,来说两句吧...