解决多节点定时任务重复执行问题

您所在的位置:网站首页 定时任务并发问题怎么解决的呢 解决多节点定时任务重复执行问题

解决多节点定时任务重复执行问题

2024-07-13 11:29| 来源: 网络整理| 查看: 265

背景

在系统开发的初期,通常都是一个单体的架构,后面随着业务的发展,单体架构已经扛不住业务的压力。慢慢的会向微服务的方向去发展,在多节点的情况下,就会出现多个节点的定时任务可能会重复执行的情况。在这种情况下面就会造成定时任务在同一时间点执行多次,造成业务重复执行的情况发生。

1、Shedlock基本介绍

相对于xxl-job,已经我们熟知的quarz,Shedlock的集成更加的轻量,同时也不需要对服务进行过多的改造,我们当时在技术选型的时候就是使用Shedlock。 Shedlock从严格意义上来说,并不是一个分布式任务调度框架,设计的初衷也不是作为一个调度框架,而是一种分布式锁。所谓的分布式锁,解决的核心问题就是各个节点中无法通信的痛点。各个节点并不知道这个定时任务有没有被其他节点的定时器执行,所以理论上只需要有一个各个节点都能够访问到的资源,用这个资源去标记这个定时任务有没有执行就可以了。 Shedlock也有很多种方案: JdbcTemplate Mongo DynamoDB DynamoDB 2 ZooKeeper (using Curator) Redis (using Spring RedisConnectionFactory) Redis (using Jedis) Hazelcast Couchbase ElasticSearch CosmosDB Cassandra Multi-tenancy 我们选用的是JdbcTemplate方式

2.具体的使用

1.新建数据库表

CREATE TABLE shedlock( name VARCHAR(64), lock_until TIMESTAMP(3) NULL, locked_at TIMESTAMP(3) NULL, locked_by VARCHAR(255), PRIMARY KEY (name) )

2.pom.xml文件中引入依赖

net.javacrumbs.shedlock shedlock-spring 2.3.0 net.javacrumbs.shedlock shedlock-provider-jdbc-template 2.3.0

3.在main启动类上加上下面两个注解

@EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "PT30S")

4在数据源的配置类中新增bean类LockProvider

@Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider(dataSource); }

5.在定时任务上面加上@SchedulerLock注解

@Scheduled(cron = "${server.scheduledSendEmail.cron}") @SchedulerLock(name = "scheduledSendEmail", lockAtMostFor = 10 * 60 * 1000, lockAtLeastFor = 5 * 60 * 1000) public void scheduledSendEmail() { logger.debug("定时任务scheduledSendEmail开启"); noticeEmailService.noticeEmail(); }

引用的流程就直接完成

3.原理讲解

1.总结原理 shedLock通过JdbcTemplate的方式实现分布式锁的原理简述:利用数据库表主键的唯一性,多个节点进行数据新增或者数据跟新的时候,通过是否新增或者跟新到数据来获取锁,获取到锁的节点进行定时任务,没有获取到锁的节点不会进行等待,而是直接跳过该任务(即注解的方法)。 2.源码分析 通过@SchedulerLock注解,每次执行定时任务之前都会进入到下面的方法中(通过AOP的方式) 在这里插入图片描述找到DefaultLockManager类,断点进去,找到doLock方法,里面的核心为insertRecord方法和updateRecord方法,这个就是各个节点获取数据库锁的关键 在这里插入图片描述具体的可以跟踪到具体的方法中,看具体的sql执行,下面看一下update的sql 在这里插入图片描述这里可以看出,进行跟新操作的时候,sql语句的where条件是有name(表主键)和lock_until,其中主键是为了保证一个节点获取倒锁,lock_until是为了判断当前的时间是否已经到了结束时间而结束当前任务(可以避免死锁) 3.直接中lockAtMostFor ,lockAtLeastFor 的含义 lockAtMostFor 成功执行任务的节点所能拥有独占锁的最长时间,单位是毫秒ms lockAtLeastFor 成功执行任务的节点所能拥有独占所的最短时间,单位是毫秒ms

shedlockd的优点:通过注解的方式,把所有的一切都交给框架处理,使得代码不会受到影响,更加符合非侵入式编程的思想,使得代码更加简洁明了。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3