任务调度(2)- Spring搭配Shedlock实现分布式定时任务锁

在Spring中,配置@EnableScheduling和@Scheduled之后,就能实现定时任务的功能(任务调度(1)-Spring @Scheduled详解 - 掘金 (juejin.cn))。

但是现在的服务实例一般都是部署多个实例,也就是具有水平扩展的能力。如果多个服务实例都在运行定时任务,会产生

  1. 资源的浪费
  2. 定时任务的重复执行

所以需要一种机制来保障多个服务实例之间的定时任务正常、合理地运行。

Shedlock

ShedLock(lukas-krecan/ShedLock: Distributed lock for your scheduled tasks (github.com))的出现就是为了解决上述问题,它可以确保你的计划任务在同一时间最多执行一次。如果一个任务正在一个节点上执行,它就会获得一个锁,防止另一个节点(或线程)执行相同的任务。如果一个任务已经在一个节点上执行,其他节点上的执行不会等待,只是被跳过。

ShedLock使用外部存储,如下所示:

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作为外部锁)

    <dependency>
        <groupId>net.javacrumbs.shedlock</groupId>
        <artifactId>shedlock-spring</artifactId>
    </dependency>

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

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

3 配置文件

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.MysqlDataSource

4 启动类添加注解

@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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值