使用SchedulerLock+Redis实现分布式调度锁的完整方案

SchedulerLock是一个轻量级的分布式锁库,主要用于确保在分布式环境中的定时任务同一时间只在一个节点上执行。结合Redis作为锁的存储后端,可以构建一个高效可靠的分布式调度系统。

本人是用版本,4.44.0

一、核心概念与原理

1.1 SchedulerLock的作用

SchedulerLock确保任务在同一时刻最多执行一次。如果一个任务正在一个节点上执行,则它将获得一个锁,该锁将阻止从另一个节点(或线程)执行同一任务。如果一个任务已经在一个节点上执行,则在其他节点上的执行不会等待,只需跳过它即可1。

 

1.2 工作原理

锁获取:当某个服务器尝试执行定时任务时,ShedLock会尝试在Redis中为该任务设置一个锁(通过设置一个具有过期时间的键)

 

任务执行:获取到锁的服务器会执行定时任务

 

锁释放:任务执行完成后,获取到锁的服务器会释放锁(ShedLock会自动处理锁的过期和释放)4

 

二、实现步骤

2.1 添加依赖

xml

<!-- Spring Data Redis -->

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

 

<!-- ShedLock核心 -->

<dependency>

    <groupId>net.javacrumbs.shedlock</groupId>

    <artifactId>shedlock-spring</artifactId>

    <version>4.42.0</version>

</dependency>

 

<!-- Redis锁提供者 -->

<dependency>

    <groupId>net.javacrumbs.shedlock</groupId>

    <artifactId>shedlock-provider-redis-spring</artifactId>

    <version>4.42.0</version>

</dependency>

2.2 配置Redis连接

在application.yml中配置Redis连接信息:

 

yaml

spring:

  redis:

    host: localhost

    port: 6379

    database: 0

    jedis:

      pool:

        max-active: 8

        max-wait: -1

        max-idle: 8

        min-idle: 0

    timeout: 10000

2.3 配置SchedulerLock

创建配置类启用SchedulerLock并配置Redis锁提供者:

 

java

@Configuration

@EnableScheduling

@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")

public class ShedLockConfig {

    

    @Bean

    public LockProvider lockProvider(RedisConnectionFactory connectionFactory) {

        return new RedisLockProvider(connectionFactory, "your-env-name");

    }

}

2.4 在启动类上添加注解

java

@SpringBootApplication

@EnableScheduling

public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }

}

三、使用SchedulerLock注解

3.1 基本用法

java

@Scheduled(cron = "0 */5 * * * *") // 每5分钟执行一次

@SchedulerLock(name = "myTask", lockAtMostFor = "PT30S", lockAtLeastFor = "PT10S")

public void myTask() {

    // 任务逻辑

}

3.2 注解参数详解

name:锁的唯一标识符,必须指定8

lockAtMostFor:锁的最大保持时间(ISO-8601格式),即使任务执行完成或崩溃,锁也将在指定时间后自动释放1

 

lockAtLeastFor:锁的最小保持时间,防止任务被频繁触发8

 

lockAtMostForString/lockAtLeastForString:支持Spring属性占位符的动态配置8

 

3.3 时间格式说明

"PT30S":30秒

 

"PT5M":5分钟

 

"PT1H":1小时4

 

四、高级配置与优化

4.1 线程池配置

为避免多定时任务积压,可以配置线程池:

 

java

@Configuration

public class ScheduleConfig implements SchedulingConfigurer {

    

    @Override

    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));

    }

}

4.2 多环境支持

在不同环境(dev/test/prod)中使用不同的锁前缀

@Bean

public LockProvider lockProvider(RedisConnectionFactory connectionFactory) {

    return new RedisLockProvider(connectionFactory, System.getProperty("spring.profiles.active"));

}

4.3 锁监控

可以使用Redis命令查看锁状态:

 

bash

KEYS shedlock:*

五、生产环境建议

锁超时设置:lockAtMostFor应大于任务最长运行时间7

 

Redis监控:监控Redis锁的竞争情况7

 

动态配置:通过cron = "${...}"实现外部化定时策略7

 

幂等设计:即使锁失效导致任务重复执行,也应保证业务逻辑的幂等性7

 

六、常见问题解决

锁不生效:检查是否遗漏了@EnableScheduling或@EnableSchedulerLock注解1

 

任务不执行:可能是线程池配置问题,检查任务是否被积压5

 

Redis连接问题:确保Redis服务可用且配置正确3

 

通过以上配置,你可以轻松地在Spring Boot应用中实现基于Redis的分布式调度锁,确保定时任务在分布式环境中的正确执行

 

Logo

更多推荐