在Spring中,配置@EnableScheduling和@Scheduled之后,就能实现定时任务的功能(任务调度(1)-Spring @Scheduled详解 - 掘金 (juejin.cn))。
但是现在的服务实例一般都是部署多个实例,也就是具有水平扩展的能力。如果多个服务实例都在运行定时任务,会产生
- 资源的浪费定时任务的重复执行
所以需要一种机制来保障多个服务实例之间的定时任务正常、合理地运行。
ShedlockShedLock(lukas-krecan/ShedLock: Distributed lock for your scheduled tasks (github.com))的出现就是为了解决上述问题,它可以确保你的计划任务在同一时间最多执行一次。如果一个任务正在一个节点上执行,它就会获得一个锁,防止另一个节点(或线程)执行相同的任务。如果一个任务已经在一个节点上执行,其他节点上的执行不会等待,只是被跳过。
ShedLock使用外部存储,如下所示:
Lock Providers
JdbcTemplateR2DBCMicronaut Data JdbcMongoDynamoDBDynamoDB 2ZooKeeper (using Curator)Redis (using Spring RedisConnectionFactory)Redis (using Jedis)HazelcastCouchbaseElasticSearchCosmosDBCassandraConsulArangoDBNeo4jEtcdApache IgniteMulti-tenancyIn-Memory
ShedLock不是一个分布式调度器。请注意,ShedLock不是也永远不会是成熟的调度器,它只是一个锁而已
ShedLock被设计用于这样的情况:你的调度任务还没有准备好被并行执行,但可以安全地重复执行
此外,锁是基于时间的,ShedLock假定节点上的时钟是同步的。
与Spring的结合 1 创建数据库和表CREATE TABLE `shedlock` ( `name` varchar(64) NOT NULL, `lock_until` timestamp(3) NULL DEFAULT NULL, `locked_at` timestamp(3) NULL DEFAULT NULL, `locked_by` varchar(255) DEFAULT NULL, PRIMARY KEY (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;2 引入依赖(这里使用MySQL作为外部锁)
3 配置文件net.javacrumbs.shedlock shedlock-springnet.javacrumbs.shedlock shedlock-provider-jdbc-templatemysql mysql-connector-java
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/shedlock?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull username: xxx password: xxx type: com.mysql.cj.jdbc.MysqlDataSource4 启动类添加注解
@SpringBootApplication @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "PT30S") public class ShedlockMain { public static void main(String[] args) { // ... } }5 提供provider
@Configuration public class SchedulerConfiguration { @Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider(JdbcTemplateLockProvider.Configuration.builder().withJdbcTemplate(new JdbcTemplate(dataSource)).build() ); } }6 实际运行定时任务的代码
@Component public class TaskScheduler { @Scheduled(cron = "0/10 * * * * ?") @SchedulerLock(name = "task", lockAtLeastFor = "2000", lockAtMostFor = "5000") public void scheduledTask() { // ... } }
通过如上配置,就可以很简单的与Spring提供的调度进行结合,实现分布式锁。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)