-
Java中实现分布式定时任务
定时器Scheduler在平时使用比较频繁,在springboot中,配置好@Scheduled和@EnableScheduling之后,定时器就能正常执行,实现定时任务的功能。
但是在这样的情况下:如果开发的服务需要水平部署实现负载均衡,那么定时任务就会同时在多个服务实例上运行,那么一方面,可能由于定时任务的逻辑处理需要访问公共资源从而造成并发问题;另一方面,就算没有并发问题,那么一个同样的任务多个服务实例同时执行,也会造成资源的浪费。因此需要一种机制来保证多个服务实例之间的定时任务正常、合理地执行。
本文以shedlock为例,来实现分布式定时任务的控制。
ShedLock可以保证多个同样的定时任务在多个服务实例之间最多只执行一次,是一个在分布式环境中保证定时任务合理执行的框架,我们可以叫它分布式定时任务锁。
ShedLock的实现原理是采用公共存储实现的锁机制,使得同一时间点只有第一个执行定时任务的服务实例能执行成功,并在公共存储中存储"我正在执行任务,从什么时候(预计)执行到什么时候",其他服务实例执行时如果发现任务正在执行,则直接跳过本次执行,从而保证同一时间一个任务只被执行一次。
ShedLock的公共存储目前支持的有:
Monogo
DynamoDB
JdbcTemplate
ZooKeeper (using Curator)
Redis (using Spring RedisConnectionFactory)
Redis (using Jedis)
Hazelcast
<!-- shedlock start --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>4.11.1</version> </dependency> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jdbc-template</artifactId> <version>4.11.1</version> </dependency> <!-- shedlock end -->
第二步添加配置类
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.annotation.Resource; import javax.sql.DataSource; import java.util.TimeZone; /** * @descrition shedlock配置类 * @since 2021-01-10 22:39 */ @Configuration public class ShedLockConfig { @Resource private DataSource dataSource; /** * @description * @date 2021/1/10 22:39 */ @Bean public LockProvider lockProvider() { return new JdbcTemplateLockProvider( JdbcTemplateLockProvider.Configuration.builder() .withJdbcTemplate(new JdbcTemplate(dataSource)) .withTimeZone(TimeZone.getTimeZone("GMT+8")) .build() ); } }
第三步,添加公共存储,前面我们说过shedlock支持多种公共存储作为锁,本文我们以mysql为例
CREATE TABLE shedlock ( NAME VARCHAR ( 64 ) NOT NULL, lock_until TIMESTAMP ( 3 ) NOT NULL, locked_at TIMESTAMP ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), locked_by VARCHAR ( 255 ) NOT NULL, PRIMARY KEY ( NAME ) );
第四步,添加具体任务类
import lombok.extern.slf4j.Slf4j; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; /** * @author shane * @date 2021/1/10 23:39 */ @Slf4j @Component public class TestJob { /** * @description 每隔1min打印一次 * @date 2021/1/10 23:39 */ @Scheduled(cron = "0 0/1 * * * ?") // lockAtMostFor为锁默认持有时间,会覆盖启动类中的默认持有时间 @SchedulerLock(name = "demo", lockAtMostFor = "70m") public void print() throws InterruptedException { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 log.warn("当前时间:"+df.format(new Date())); } }
接着,我们复制一份代码,分别启动两个实例来看结果


数据库记录

@SchedulerLock注解参数说明
name:定时任务的名字,就是数据库中的内个主键
lockAtMostFor:锁的最大时间单位为毫秒
lockAtLeastFor:锁的最小时间单位为毫秒
对了,还有启动类的配置lockAtMostFor:锁的最大时间单位为毫秒
lockAtLeastFor:锁的最小时间单位为毫秒
@SpringBootApplication @MapperScan("com.example.test.mapper") @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "10m") // 默认的锁的时间 public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } }
参考出处: https://www.jianshu.com/p/941416645606
shedlock的github地址:https://github.com/lukas-krecan/ShedLock
最新更新
求1000阶乘的结果末尾有多少个0
详解MyBatis延迟加载是如何实现的
IDEA 控制台中文乱码4种解决方案
SpringBoot中版本兼容性处理的实现示例
Spring的IOC解决程序耦合的实现
详解Spring多数据源如何切换
Java报错:UnsupportedOperationException in Col
使用Spring Batch实现批处理任务的详细教程
java中怎么将多个音频文件拼接合成一个
SpringBoot整合ES多个精确值查询 terms功能实
数据库审计与智能监控:从日志分析到异
SQL Server 中的数据类型隐式转换问题
SQL Server中T-SQL 数据类型转换详解
sqlserver 数据类型转换小实验
SQL Server数据类型转换方法
SQL Server 2017无法连接到服务器的问题解决
SQLServer地址搜索性能优化
Sql Server查询性能优化之不可小觑的书签查
SQL Server数据库的高性能优化经验总结
SQL SERVER性能优化综述(很好的总结,不要错
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比