首页 > 其他分享 >Spring Boot集成ShedLock实现分布式定时任务

Spring Boot集成ShedLock实现分布式定时任务

时间:2024-12-11 09:30:37浏览次数:10  
标签:spring ShedLock Boot springframework 任务 实例 Spring import

1、什么是ShedLock?
ShedLock 是一个 Java 库,通常用于分布式系统中,确保定时任务(Scheduled Tasks)在集群环境下只被某一个实例执行一次。它通过在共享资源(例如数据库或分布式缓存)中添加锁的方式,避免多个实例同时执行相同的任务

ShedLock 的工作原理
1.分布式锁:

在任务开始时,ShedLock 会尝试在数据库(或其他存储)中创建一个锁。
如果某个实例成功获取锁,则只有它能执行该任务。

2.锁的生命周期:

锁会有一个明确的过期时间(锁的持有时间,lockAtLeastFor 和 lockAtMostFor 参数配置)。
锁过期后,即使任务异常终止,其他实例也可以重新获取锁。

3.支持的存储:

支持多种锁存储,包括数据库(如 MySQL、PostgreSQL)、Redis、MongoDB 等。

应用场景
1、分布式定时任务控制
在分布式环境中,多个实例会同时调度定时任务。如果没有控制,可能导致任务重复执行。ShedLock 确保只有一个实例能运行任务。
例如:
生成日报表的定时任务。
清理过期数据的批处理任务。

2、避免重复任务执行
即使在单实例环境中,也可以使用 ShedLock 避免因意外重启或配置错误导致同一任务被多次触发。

3、事件驱动任务的幂等性
当某些任务需要对同一事件触发处理时,使用 ShedLock 可以确保一个事件只被处理一次。

4、任务重试机制
如果任务需要重试(例如在发生错误时),ShedLock 能避免多个实例同时重试相同任务。

2、代码工程

实验目的
使用ShedLock 来确保在分布式环境中只有一个实例能运行任务

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.1</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>shedlock</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-spring</artifactId>
            <version>5.5.0</version>
        </dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-provider-jdbc-template</artifactId>
            <version>5.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
    </dependencies>
</project>

config

package com.demo.config;

import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class ShedLockConfig {

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(
            JdbcTemplateLockProvider.Configuration.builder()
                .withJdbcTemplate(new JdbcTemplate(dataSource))
                .usingDbTime() // Works with PostgreSQL, MySQL, MariaDb, MS SQL, Oracle, HSQL, H2, DB2, and others
                .build()
        );
    }
}

cron

package com.demo.cron;

import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SchedulerConfig {

    @Scheduled(cron = "0 0/1 * * * ?")
    @SchedulerLock(name = "scheduledTaskName", lockAtMostFor = "PT10M", lockAtLeastFor = "PT1M")
    public void scheduledTask() {
        //  some logic code
        System.out.println("Executing scheduled task");
    }

}

@Scheduled(cron = “0 0/1 * * * ?”)

1、定义定时任务的调度时间。

2、表达式含义:任务每分钟的整点触发,例如 12:00、12:01、12:02。

3、注意:多个实例(分布式环境)都会在同一时间调度到此任务,但通过 ShedLock 确保只有一个实例能真正执行。

@SchedulerLock

1、锁的最短持有时间为 1分钟。

2、即使任务提前完成,锁仍会持有至少 1 分钟,防止其他实例快速重复执行任务。

3、锁的最长持有时间为 10分钟。

4、如果任务运行超出 10 分钟,即使没有主动释放锁,也会自动过期,其他实例可以继续获取锁。

5、定义锁的唯一标识。共享存储(如数据库或 Redis)中会记录此锁的状态。

6、使用 ShedLock 来管理分布式锁。

7、name = “scheduledTaskName”:

8、lockAtMostFor = “PT10M”:

9、lockAtLeastFor = “PT1M”:

任务逻辑

1、System.out.println(“Executing scheduled task”); 是任务的业务逻辑。

2、此逻辑只会在获得锁的实例上执行。

配置文件
node1节点

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
server.port=8081

node2节点

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
server.port=8082

3、测试
1、启动node1节点
java -jar myapp.jar --spring.profiles.active=node1

2、启动node2节点
java -jar myapp.jar --spring.profiles.active=node2

通过控制台观察日志,可以发现,2个实例交替获取到锁执行,而不是同一时刻一起执行

4、注意事项

  • 任务时间控制: 确保任务的实际执行时间小于 lockAtMostFor,否则任务可能被其他实例重复执行。

  • 幂等性: 任务逻辑应尽量设计为幂等的(重复执行不会产生副作用),以应对锁机制的潜在异常情况。

  • 存储配置: 确保使用高可用的锁存储(如数据库或 Redis),否则锁机制可能失效。

标签:spring,ShedLock,Boot,springframework,任务,实例,Spring,import
From: https://blog.csdn.net/weixin_46619605/article/details/144389305

相关文章

  • springboot内容总结
    springboot源码学习过程记录springboot程序是通过SpringApplication这个类来启动一个Java主程序当前是基于springboot的2.6.13版本来学习的调用SpringApplication的构造函数创建对象,然后调用run方法 publicSpringApplication(ResourceLoaderresourceLoader,Class<?>...p......
  • Springboot+vue仿腾讯在线会议系统,支持在线会议(包括语音和投屏)以及文字聊天功能,最近
    支持在线会议(包括语音和投屏)以及文字聊天功能,最近完成的项目,算是比较小众的项目,功能比较完善,美中不足的就是页面ui设计一般,可先看项目的完整演示项目演示:https://www.bilibili.com/video/BV1ALsre3Epm/小众项目,拿来做毕设简直是嘎嘎乱杀,项目质量是很好可以保证的,大家可以看......
  • 基于springboot实现的古诗词系统源码
    项目简介基于springboot实现的古诗词系统,主要分为管理员和用户两种角色,管理员可以对古诗词类型,古诗词标签,古诗词作者,朝代,古诗文信息等基础数据进行管理,可以发布古诗文征文活动,可以查看用户参与活动上传的诗文内容,并且进行审核,审核通过的文章会进入到现代诗文栏目里面;普通会员......
  • Spring Guava数据流转换与处理9
    在现代开发中,数据流的转换与处理是一个非常常见的需求。无论是从文件读取数据、接收用户输入,还是从数据库提取信息,数据往往需要进行一系列转换和处理。Guava提供了许多工具和类,能够简化这一过程,尤其是在处理数据时,它的链式调用风格使得数据流的处理更加清晰、优雅。通过结合Gua......
  • SpringBoot的Bean类三种注入方式(附带LomBok注入)
    SpringBoot的Bean类三种注入方式(附带LomBok注入)在SpringBoot中,Bean的注入方式主要包括构造函数注入(ConstructorInjection)、字段注入(FieldInjection)以及Setter方法注入(SetterInjection)。每种注入方式都有其特点和适用场景。此外,Lombok提供了一种简化依赖注入的方......
  • 私活更好用:SpringBoot开源项目!!
    今天分享一款非常香的SpringBoot大屏开源项目,非常适合接私活用。这是一款基于SpringBoot+代码生成器的快速开发平台!采用前后端分离架构:SpringBoot,Mybatis,Shiro,JWT,Vue&AntDesign。强大的代码生成器让前端和后台代码一键生成,不需要写任何代码,保持一贯的强大,绝对是全栈开发福音!!......
  • spring-boot-starter-tomcat 的依赖项
    以下是SpringBoot1.4.3.RELEASE版本中 spring-boot-starter-tomcat 的依赖项及其功能描述:ArtifactIdPurposetomcat-embed-core提供嵌入式Tomcat的核心功能,使应用程序能够通过嵌入式Tomcat运行。tomcat-embed-el提供嵌入式Tomcat的表达式语言(EL)支持,用于解......
  • spring-boot-starter-web 的依赖项
    以下是SpringBoot1.4.3.RELEASE版本中 spring-boot-starter-web 的依赖项及其功能描述:ArtifactIdPurposespring-boot-starter提供SpringBoot应用的核心依赖,包括自动配置支持和日志功能,以简化SpringBoot应用的开发。spring-boot-starter-tomcat提供嵌入式......
  • SpringBoot全局配置文件
    SpringBoot使用一个application.properties或者application.yaml的文件作为全局配置文件。application.properties配置文件application.properties文件中定义springboot项目的相关属性注入系统变量,系统属性等server.address=80server.port=8080server.datasource.driver......
  • spring-boot-dependencies的依赖项
    以下是SpringBoot1.4.3.RELEASE版本中spring-boot-dependencies的依赖项及其功能描述,按artifact名称排序:ArtifactNamePurposeactivemq开放源代码消息代理,实现Java消息服务(JMS)规范。antlr2用于构建语言识别器、编译器和翻译器的工具。appengine提供Googl......