Spring Cloud Alibaba -- 分布式定时任务解决方案(轻量级、快速构建)(ShedLock 、@SchedulerLock )

文章目录

  • 一、 ShedLock简介
  • 二、 @SchedulerLock
  • 三、基于Mysql方式使用步骤
    • 1.建表
    • 2.引入依赖
    • 3.Mysql连接配置
    • 4.ScheduledLock配置
    • 5.启动类配置
    • 6.创建定时任务
    • 7.启动多个项目服务进行测试
    • 8.SchedulerLock注解说明
  • 四、使用注意事项


一、 ShedLock简介

ShedLock 是一个用于 Java 和 Spring Boot 应用的开源分布式锁库,旨在确保在分布式环境下定时任务能够被安全地调度和执行。它的主要目的是防止在多节点环境中定时任务的重复执行,通过使用锁机制来实现这一目标。ShedLock 的设计哲学是轻量级和易于集成,特别适合那些不需要复杂调度逻辑的场景,但需要确保定时任务的执行不会发生竞态条件或资源冲突。

ShedLock 的特点
1、分布式锁:ShedLock 使用外部存储(如数据库或 Redis)来实现分布式锁,确保即使在多台服务器上运行相同的服务,同一时刻只有一个实例执行特定的定时任务。

2、轻量级:相对于像 Quartz 这样的全面调度框架,ShedLock 更专注于解决分布式定时任务的互斥执行问题,提供了简单的接口和较少的配置选项。

3、易用性:ShedLock 与 Spring Boot 的集成非常平滑,通过注解和自动配置简化了定时任务的管理,只需要使用@SchedulerLock即可。

4、Cron 和固定间隔支持:虽然 ShedLock 的调度功能相对简单,但它仍然支持 Cron 表达式和固定间隔的定时任务调度。

5、健壮性:ShedLock 能够处理任务失败的情况,提供重试机制,并且能够优雅地处理节点故障。


二、 @SchedulerLock

@SchedulerLock 注解是一个分布式锁的框架,结合@Scheduled 注解,可以保证任务同一时间,在多个节点上只会执行一次。该框架支持多种分布式锁的实现,比如Jdbc、Zookeeper、Redis等。
原理图如下:
在这里插入图片描述


三、基于Mysql方式使用步骤

1.建表

建表语句代码如下:

# 建表sql
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)
);

2.引入依赖

<!--    shedlock的依赖    -->
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-spring</artifactId>
            <version>4.23.0</version>
        </dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-provider-jdbc-template</artifactId>
            <version>4.23.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>

3.Mysql连接配置

# 应用服务 WEB 访问端口
server.port=8080
spring.datasource.url=jdbc:mysql://192.168.10.26:19131/ch?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=sa123456
spring.datasource.driver-class=com.mysql.cj.jdbc.Driver

4.ScheduledLock配置

package com.example.schedulerlock.config;

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

import javax.sql.DataSource;
import java.util.TimeZone;

/**
 * @Title: ScheduledLockConfig
 * @Author ch
 * @Date 2024/7/9 11:13
 * @description:
 */
@Configuration
public class ScheduledLockConfig {

    @Autowired
    private DataSource dataSource;

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

5.启动类配置

package com.example.schedulerlock;

import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "3m")
public class MySchedulerLockApplication {

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

}

6.创建定时任务

package com.example.schedulerlock.job;

import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.joda.time.DateTime;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * @Title: SpringJob
 * @Author ch
 * @Date 2024/7/9 11:19
 * @description:
 */
@Slf4j
@Component
public class SpringJob {
    /**
     * 每5分钟跑一次
     */
    @Scheduled(cron = "0 */5 * * * ?")
    @SchedulerLock(name = "SpringJob.job1", lockAtMostFor = "2m", lockAtLeastFor = "1m")
    public void job1() {
        log.info("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job1...");
    }

    /**
     * 每5秒跑一次
     */
    @Scheduled(fixedRate = 5000)
    @SchedulerLock(name = "SpringJob.job2", lockAtMostFor = "4s", lockAtLeastFor = "4s")
    public void job2() {
        log.info("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job2...");
    }

    /**
     * 上次跑完之后隔5秒再跑
     * @throws InterruptedException
     */
    @Scheduled(fixedDelay = 5000)
    @SchedulerLock(name = "SpringJob.job3", lockAtMostFor = "4s", lockAtLeastFor = "4s")
    public void job3() throws InterruptedException {
        log.info("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job3...");
        Thread.sleep(10000);
    }
}

7.启动多个项目服务进行测试

在这里插入图片描述

8.SchedulerLock注解说明

name:用来标注一个定时服务的名字,被用于写入数据库作为区分不同服务的标识,如果有多个同名定时任务则同一时间点只有一个执行成功。

lockAtMostFor: 这个属性指定了锁最多可以持有的时间长度。如果任务执行时间超过了给定时间,锁也将强制释放,以便其他等待的任务有机会获取锁并执行。但是,这也意味着如果任务执行时间超过锁的持有时间,可能会出现并发执行的情况。

lockAtLeastFor: 这个属性指定了锁至少可以持有的时间长度。这可以防止在任务执行结束后立即有另一个任务尝试获取相同的锁,从而产生不必要的锁争用。


四、使用注意事项

1、@SchedulerLock结合@Scheduled(cron = …):
利用 Cron 表达式来精确控制任务的执行时间点,同时利用 SchedulerLock 来保证任务执行的互斥性。Cron 表达式提供了更精细的时间控制,可以避免任务堆叠,而 SchedulerLock 则确保了即使在多个节点上部署,同一时刻也只有一个任务实例在运行。

2、@SchedulerLock结合@Scheduled(fixedRate = …)和(fixedDelay = …):
fixedRate 和fixedDelay 它们分别按照固定速率和固定延迟执行任务。这意味着无论上一次任务执行是否完成,到达设定的时间间隔后都会触发下一次执行。这种模式下,如果任务执行时间超过设定的间隔,可能会出现任务堆叠的情况,即多个任务实例同时运行。

SchedulerLock 的作用机制在于它会在任务开始执行前尝试获取一个锁,只有获取到锁的任务实例才能继续执行。执行完成后,锁会被释放,下一个任务实例才有机会获取锁并执行。这一机制非常适合保证任务的互斥执行,但在 fixedRate 或 fixedDelay 的场景下,由于任务的触发不依赖于前一个任务的完成,而是严格基于时间间隔,所以 SchedulerLock 只能保证每次任务开始执行时的互斥性,而无法直接控制任务的触发频率。

在分布式环境中使用 fixedRate 或 fixedDelay 时,如果不加额外控制,可能会导致多个节点上的任务实例几乎同时触发,从而违反了分布式定时任务的基本要求——确保同一时刻只有一个任务实例运行。此时,即使使用了 SchedulerLock,也可能因为多个节点几乎同时尝试获取锁而增加锁的争用,进而影响性能。

总之,SchedulerLock 与 fixedRate 或 fixedDelay 的结合使用需要谨慎,因为两者的设计目的和工作原理不同,可能不会达到预期的效果。在分布式定时任务的场景下,推荐使用 SchedulerLock 结合 Cron 表达式的方式,以获得更好的互斥性和时间控制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/788700.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中职网络安全B模块渗透测试server2003

通过本地PC中渗透测试平台Kali对服务器场景Windows进⾏系统服务及版本扫描渗透测 试&#xff0c;并将该操作显示结果中Telnet服务对应的端⼝号作为FLAG提交 使用nmap扫描发现目标靶机开放端口232疑似telnet直接进行连接测试成功 Flag&#xff1a;232 通过本地PC中渗透测试平台…

VMware取消中文支持,替换vSAN解决方案提上日程!

What is vSAN &#xff1f; 是一款软件定义的企业存储解决方案&#xff0c;支持超融合基础架构系统。vSAN与VMware vSphere 完全集成在一起&#xff0c;作为ESXi Hypervisor内的分布式软件层&#xff0c;通过整合、池化ESXi各个主机上的存储资源&#xff0c;为vSphere虚拟化平…

Apache中使用SSI设置

先停服务在修改httpd.conf&#xff0c;备份下 Apache\Apache24\conf 设置httpd.conf LoadModule ssl_module modules/mod_ssl.so 取消该命令前的注释符# AddType text/html .shtml AddOutputFilter INCLUDES .shtml 取消该命令前的注释符# 加入html AddType text/html .…

mov视频怎么改成mp4?把mov改成MP4的四个方法

mov视频怎么改成mp4&#xff1f;选择合适的视频格式对于确保内容质量和流通性至关重要。尽管苹果公司的mov格式因其出色的视频表现备受赞誉&#xff0c;但在某些情况下&#xff0c;它并非最佳选择&#xff0c;因为使用mov格式可能面临一些挑战。MP4格式在各种设备&#xff08;如…

中职网络安全wire0077数据包分析

从靶机服务器的FTP上下载wire0077.pcap&#xff0c;分析该文件&#xff0c;找出黑客入侵使用的协议&#xff0c;提交协议名称 SMTP 分析该文件&#xff0c;找出黑客入侵获取的zip压缩包&#xff0c;提交压缩包文件名 DESKTOP-M1JC4XX_2020_09_24_22_43_12.zip 分析该文件&…

Mysql练习题目【7月10日更新】

七、Mysql练习题目 https://zhuanlan.zhihu.com/p/38354000 1. 创建表 创建学生表 mysql> create table if not exists student(-> student_id varchar(255) not null,-> student_name varchar(255) not null,-> birthday date not null,-> gender varchar(…

算法金 | 12 个最佳 Python 代码片段,帮我完成工作自动化,香~

​大侠幸会幸会&#xff0c;我是日更万日 算法金&#xff1b;0 基础跨行转算法&#xff0c;国内外多个算法比赛 Top&#xff1b;放弃 BAT Offer&#xff0c;成功上岸 AI 研究院 Leader&#xff1b; Python是一种多功能的编程语言&#xff0c;它提供了各种功能和库来有效地自动化…

【分布式系统管理框架】Zookeeper集群

1、Zookeeper &#xff08;1&#xff09;Zookeeper定义 Zookeeper是一个开源的&#xff0c;为分布式框架提供协调服务的Apache项目。 &#xff08;2&#xff09;Zookeeper工作机制 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架…

使用linux的mail命令发送html格式的邮件

1、关闭本机的sendmail服务或者postfix服务 #执行下面的命令&#xff0c;各位大侠都对号入座吧 #sendmial service sendmail stop chkconfig sendmail off #postfix service postfix stop chkconfig postfix off#再狠一点就直接卸载吧.. yum remove sendmail yum remove postf…

大小端详解

引例 我们知道整形(int)是4个字节&#xff0c;例如随便举个例子&#xff1a;0x01020304&#xff0c;它一共占了四个地址位&#xff0c;01,02,03,04分别占了一个字节&#xff08;一个字节就对应了一个地址&#xff09;。 那么就会有个问题&#xff1a;我们的01到底是存储在高地…

20_Inception V3深度学习图像分类算法

回顾GoogleNet:传送门 1.1 介绍 InceptionV3是Google开发的一种深度卷积神经网络架构&#xff0c;它是Inception系列网络中的第三代模型&#xff0c;由Christian Szegedy等人在论文《Rethinking the Inception Architecture for Computer Vision》中提出&#xff0c;该论文发…

在vue3中,手写父子关联,勾选子级父级关联,取消只取消当前子级,父节点不动

树形控件选择子级勾选父级&#xff0c;以及所有子级&#xff0c; 取消勾选仅取消子级 在项目中&#xff0c;可能会遇到这种场景&#xff0c;比如权限配置的时候&#xff0c;页面权限和菜单权限以tree的形式来配置&#xff0c;而且不用半选&#xff0c;菜单在页面的下面&#xf…

基于SpringBoot构造超简易QQ邮件服务发送 第二版

目录 追加 邮箱附件 添加依赖 编码 测试 第二版的更新点是追加了 邮箱附件功能 ( 后期追加定时任务 ) 基于SpringBoot构造超简易QQ邮件服务发送(分离-图解-新手) 第一版 追加 邮箱附件 添加依赖 <!-- 电子邮件 --><dependency><groupId>org.spri…

影视行业的人工智能与-【机器学习】:案例分析

欢迎关注小知&#xff1a;知孤云出岫 目录 引言AI和ML在影视行业的当前应用AI和ML对影视行业的未来影响案例研究&#xff1a;AI生成动画视频目标工具和库数据收集模型训练视频生成 结论参考文献 引言 人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09…

java如何实现一个死锁 ?

死锁(Deadlock)是指在并发系统中,两个或多个线程(或进程)因争夺资源而互相等待,导致它们都无法继续执行的一种状态。 一、简易代码 public class DeadlockExample {private static final Object lock1 = new Object();private

Сетунь的24条单播指令

1、Setun模拟器概述 真的&#xff0c;想搞懂一台电脑是怎么运行的&#xff0c;那就搞懂它的指今集是怎么跑的&#xff0c;感觉很离了个大谱的&#xff0c;先看由铁氧体磁芯上的器件组成的RAM&#xff0c;容量为162个9-trit单元&#xff0c;即每个单元为9-trit&#xff0c;每页有…

Kubelet 认证

当我们执行kubectl exec -it pod [podName] sh命令时&#xff0c;apiserver会向kubelet发起API请求。也就是说&#xff0c;kubelet会提供HTTP服务&#xff0c;而为了安全&#xff0c;kubelet必须提供HTTPS服务&#xff0c;且还要提供一定的认证与授权机制&#xff0c;防止任何知…

【PB案例学习笔记】-30动态打开窗口

写在前面 这是PB案例学习笔记系列文章的第30篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

Java | Leetcode Java题解之第225题用队列实现栈

题目&#xff1a; 题解&#xff1a; class MyStack {Queue<Integer> queue;/** Initialize your data structure here. */public MyStack() {queue new LinkedList<Integer>();}/** Push element x onto stack. */public void push(int x) {int n queue.size();…

用PlantUML和语雀画UML类图

概述 首先阐述一下几个简单概念&#xff1a; UML&#xff1a;是统一建模语言&#xff08;Unified Modeling Language&#xff09;的缩写&#xff0c;它是一种用于软件工程的标准化建模语言&#xff0c;旨在提供一种通用的方式来可视化软件系统的结构、行为和交互。UML由Grady…