springboot集成shedlock分布式定时任务锁

定时器Scheduler在平时使用比较频繁,比如定时数据整理,定时向客户发送问候信息等…,定时任务的配置比较简单,比如在springboot中,配置好@Scheduled和@EnableScheduling之后,定时器就能正常执行,实现定时任务的功能。

但是在这样的情况下:如果开发的服务需要水平部署实现负载均衡,那么定时任务就会同时在多个服务实例上运行,那么一方面,可能由于定时任务的逻辑处理需要访问公共资源从而造成并发问题;另一方面,就算没有并发问题,那么一个同样的任务多个服务实例同时执行,也会造成资源的浪费。因此需要一种机制来保证多个服务实例之间的定时任务正常、合理地执行。

ShedLock介绍

ShedLock的出现就是为了解决上述问题,它可以保证多个一个定时任务在多个服务实例之间最多只执行一次,是一个在分布式环境中保证定时任务合理执行的框架。

ShedLock的实现原理是采用公共存储实现的锁机制,使得同一时间点只有第一个执行定时任务的服务实例能执行成功,并在公共存储中存储"我正在执行任务,从什么时候(预计)执行到什么时候",其他服务实例执行时如果发现任务正在执行,则直接跳过本次执行,从而保证同一时间一个任务只被执行一次。

上面提到的公共存储目前支持的有:

  • Monogo
  • DynamoDB
  • JdbcTemplate
  • ZooKeeper (using Curator)
  • Redis (using Spring RedisConnectionFactory)
  • Redis (using Jedis)
  • Hazelcast

值得注意的是,ShedLock不是一个分布式的定时任务框架,只是一个锁,用于保证分布式环境中的定时任务合理执行。贴一段原话:Please note that ShedLock is not and will never be full-fledged scheduler, it’s just a lock. If you need a distributed scheduler, please use another project. ShedLock is designed to be used in situations where you have scheduled tasks that are not ready to be executed in parallel, but can be safely executed repeatedly. For example if the task is fetching records from a database, processing them and marking them as processed at the end without using any transaction. In such case ShedLock may be right for you.

开始集成

springboot版本:2.5.5

先介绍用redis存储锁的配置方法

1.引入依赖

<!-- shedlock start -->
<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-spring</artifactId>
	<version>2.5.0</version>
</dependency>
<!-- 使用redis保存分布式任务锁 -->
<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-provider-redis-spring</artifactId>
	<version>2.5.0</version>
</dependency>
<!-- shedlock end -->

2.创建配置类

/**
 * 分布式定时调度配置
 * <p>
 * SchedulerLock 注解一共支持五个参数,分别是
 * name 用来标注一个定时服务的名字,被用于写入数据库作为区分不同服务的标识,如果有多个同名定时任务则同一时间点只有一个执行成功
 * lockAtMostFor 成功执行任务的节点所能拥有独占锁的最长时间,单位是毫秒ms
 * lockAtMostForString 成功执行任务的节点所能拥有的独占锁的最长时间的字符串表达,例如“PT14M”表示为14分钟
 * lockAtLeastFor 成功执行任务的节点所能拥有独占所的最短时间,单位是毫秒ms
 * lockAtLeastForString 成功执行任务的节点所能拥有的独占锁的最短时间的字符串表达,例如“PT14M”表示为14分钟
 */
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "PT10M")
public class SchedulerConfig {

    @Bean
    public LockProvider lockProvider(RedisTemplate redisTemplate){
        return new RedisLockProvider(redisTemplate.getConnectionFactory());
    }

}

3.使用:定时任务方法上添加@SchedulerLock注解即可

@Component
public class SchedulerTest {

    @Scheduled(cron = "* * * * * ?")
    @SchedulerLock(name = "test1")//定时任务分布式锁
    public void test1(){
        try{
            System.out.println("========================================test1 start");
            Thread.sleep(5000);
            System.out.println("========================================test1 end");
        }catch (Exception e){

        }
    }

}

完成

如果想用mysql存储锁,可以采用如下配置:

1.引入依赖

<!-- shedlock start -->
<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-spring</artifactId>
	<version>2.5.0</version>
</dependency>
<!-- 使用mysql保存分布式任务锁 -->
<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-provider-jdbc-template</artifactId>
	<version>2.5.0</version>
</dependency>
<!-- shedlock end -->

2.配置类

/**
 * 分布式定时调度配置
 * <p>
 * SchedulerLock 注解一共支持五个参数,分别是
 * name 用来标注一个定时服务的名字,被用于写入数据库作为区分不同服务的标识,如果有多个同名定时任务则同一时间点只有一个执行成功
 * lockAtMostFor 成功执行任务的节点所能拥有独占锁的最长时间,单位是毫秒ms
 * lockAtMostForString 成功执行任务的节点所能拥有的独占锁的最长时间的字符串表达,例如“PT14M”表示为14分钟
 * lockAtLeastFor 成功执行任务的节点所能拥有独占所的最短时间,单位是毫秒ms
 * lockAtLeastForString 成功执行任务的节点所能拥有的独占锁的最短时间的字符串表达,例如“PT14M”表示为14分钟
 */
@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "PT10M")
public class SchedulerConfig {

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(
                JdbcTemplateLockProvider.Configuration.builder()
                        .withJdbcTemplate(new JdbcTemplate(dataSource))
                        .withTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
                        .build()
        );
    }

}

3.创建数据表

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)
);

4.使用方式同redis,添加相关注解即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值