Spring Boot 实现分布式定时任务锁 shedlock

Spring Boot 实现分布式定时任务锁 shedlock

分布式定时任务有好几种实现,我这里用了mysql和redis来实现

我们在项目中经常要用到定时任务,当有天服务器压力过大,我们就会增加服务器的数量,这时每台服务器的定时任务都在同一时间运行,导致我们需要同一时间运行一次的定时任务跑了多次,这时就需要解决这个问题,就用到了 shedlock

下面这是我项目里写的定时任务,里面的方法没有写出来

@Component
public class TimeOutSMSScheduledLock {

    @Autowired
    public TimeOutSMSService timeOutSMSService;

	//这时定时任务
    @Scheduled(cron = "0 0 9,14 * * ?")
    public void sendSMS(){
    	//具体的方法我就不写了,你可以随便写也可以打印日志
        timeOutSMSService.timeOutSendSMS();
    }
}

1.mysql实现分布式定时任务锁

导包

<dependency>
  		<groupId>net.javacrumbs.shedlock</groupId>
  		<artifactId>shedlock-spring</artifactId>
  		<version>2.2.0</version>
  	</dependency>
  	<dependency>
  		<groupId>net.javacrumbs.shedlock</groupId>
  		<artifactId>shedlock-provider-jdbc-template</artifactId>
  		<version>2.2.0</version>
  	</dependency>  

配置,创建一个它要用到的bean

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

然后在数据库建一张表

CREATE TABLE `shedlock` (
  `name` varchar(64) NOT NULL DEFAULT '',
  `lock_until` timestamp NULL DEFAULT NULL,
  `locked_at` timestamp NULL DEFAULT NULL,
  `locked_by` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

里面有四个字段

主键name:每个定时任务的一个名字

locked_at:锁的开始时间

lock_until:锁的结束时间

再定时开始时,会更新这两个时间,在时间之内的定时是不会被执行的

Spring Boot 实现分布式定时任务锁 shedlock_第1张图片

在启动类上加@EnableSchedulerLock注解

@SpringBootApplication
//启用自带定时任务
@EnableScheduling
//定时任务锁
//defaultLockAtMostFor 指定在执行节点结束时应保留锁的默认时间使用ISO8601 Duration格式
//作用就是在被加锁的节点挂了时,无法释放锁,造成其他节点无法进行下一任务
//这里默认30s
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class CmccVoicesApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(CmccVoicesApiApplication.class, args);
    }
}

在方法上加@SchedulerLock注解

@Component
public class TimeOutSMSScheduledLock {

    @Autowired
    public TimeOutSMSService timeOutSMSService;

	//这是定时任务
    @Scheduled(cron = "0 0 9,14 * * ?")
    //参数自己根据情况设置
    @SchedulerLock(name = "sugExpiredSMS", lockAtMostFor = 1000*60*60*10, lockAtLeastFor = 1000*60*60*5)
    public void sendSMS(){
    	//具体的方法我就不写了,你可以随便写也可以打印日志
        timeOutSMSService.timeOutSendSMS();
    }
}

name:定时任务的名字,就是数据库中的内个主键
lockAtMostFor:锁的最大时间单位为毫秒
lockAtMostForString:最大时间的字符串形式,例如:PT30S 代表30秒
lockAtLeastFor:锁的最小时间单位为毫秒
lockAtLeastForString:最小时间的字符串形式

这样mysql的分布式定时任务锁就完成了

2.redis 实现分布式定时任务锁

redis其实和mysql类似,只是配置和导包的不同

导包

<!-- 分布式定时任务锁 -->
        <!-- https://mvnrepository.com/artifact/net.javacrumbs.shedlock/shedlock-spring -->
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-spring</artifactId>
            <version>4.0.4</version>
        </dependency>
        <!-- 使用redis做分布式任务 -->
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-provider-redis-spring</artifactId>
            <version>2.5.0</version>

配置 shedlock 和 redis


@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M")
public class ShedLockConfig {
 
    @Bean
    public LockProvider lockProvider(RedisTemplate redisTemplate) {
        return new RedisLockProvider(redisTemplate.getConnectionFactory());
    }

在启动类上添加注解

@SpringBootApplication
//这个是定时任务,必须要有
@EnableScheduling
public class AppsApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(AppsApplication .class, args);
    }

在定时任务上加注解@SchedulerLock,这里和mysql是一样

@Component
public class TimeOutSMSScheduledLock {

    @Autowired
    public TimeOutSMSService timeOutSMSService;

	//这是定时任务
    @Scheduled(cron = "0 0 9,14 * * ?")
    //参数自己根据情况设置
    @SchedulerLock(name = "sugExpiredSMS", lockAtMostFor = 1000*60*60*10, lockAtLeastFor = 1000*60*60*5)
    public void sendSMS(){
    	//具体的方法我就不写了,你可以随便写也可以打印日志
        timeOutSMSService.timeOutSendSMS();
    }
}

这样redis的分布式定时任务锁完成

有不对的地方请大家指出

你可能感兴趣的:(分布式,定时任务锁)