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

news2024/9/23 17:11:39

文章目录

  • 一、 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.coloradmin.cn/o/1910692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

swiftui给视图添加边框或者只给某个边设置border边框

直接使用border()就可以给一个视图添加边框效果&#xff0c;但是这种边框会给所有的边都设置上。 border()里面也可以添加属性.border(.blue, width: 5)这种就是设置颜色和宽度。 设置圆角边框 Text("1024小神").padding().cornerRadius(20).overlay(RoundedRectang…

如何在Facebook上保护你的个人资料安全?

随着社交媒体的普及和个人信息的数字化&#xff0c;保护个人资料安全成为越来越重要的议题。特别是在使用像Facebook这样的平台时&#xff0c;我们需要特别注意如何保护我们的数据免受未经授权的访问和滥用。本文将探讨一些实用的方法&#xff0c;以及如何增强你在Facebook上的…

keil mdk注释插件合集格式、时间、日期注释

文章目录 一、前言二、安装步骤2.1 解压tools.zip2.2 tools 文件解释2.3 添加注释带keil 三、配置3.1 格式化代码3.2 文件注释3.3函数注释3.4 当前日期3.5 当前时间 四、编辑注释模板4.1 编辑函数注释模板4.2 编辑C文件注释模板4.3 编辑h文件注释模板 五、为注释功能添加快捷键…

qmt量化交易策略小白学习笔记第55期【qmt编程之期权数据--获取历史期权列表】

qmt编程之获取期权数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 感谢关注&#xff0c;咨询免费开通量化回测与获取实盘权限&#xff0c;欢迎和博主联系&#xff01; 获取历史期权列表 …

Sui DeFi现状介绍

关于Sui Network Sui是基于第一原理重新设计和构建而成的L1公有链&#xff0c;旨在为创作者和开发者提供能够承载Web3中下一个十亿用户的开发平台。Sui上的应用基于Move智能合约语言&#xff0c;并具有水平可扩展性&#xff0c;让开发者能够快速且低成本支持广泛的应用开发。获…

视频监控管理平台智能边缘分析一体机视频监控系统客流统计检测算法

在当今数据驱动的时代&#xff0c;客流统计作为商业分析的重要手段&#xff0c;其准确性和实时性对于商家决策具有至关重要的影响。随着技术的发展&#xff0c;智能边缘分析一体机结合了边缘计算与深度学习技术&#xff0c;为客流统计提供了更为高效、精准的解决方案。 首先&am…

可变参数 Collections 不可变集合 Stream流

目录 1.可变参数&#xff1a; 2.Collections: 3.不可变集合&#xff1a; 4.Stream流: 1、什么是流 2、如何生成流 1.单列集合获取Stream流 2.双列集合获取Stream流 3.数组获取Stream流&#xff1a; 4.一堆零散数据&#xff1a; Stream接口中的静态方法 3.Stream流的…

【总线】AXI第九课时:介绍AXI响应信号 (Response Signaling):RRESP和 BRESP

大家好,欢迎来到今天的总线学习时间!如果你对电子设计、特别是FPGA和SoC设计感兴趣&#xff0c;那你绝对不能错过我们今天的主角——AXI4总线。作为ARM公司AMBA总线家族中的佼佼者&#xff0c;AXI4以其高性能和高度可扩展性&#xff0c;成为了现代电子系统中不可或缺的通信桥梁…

如何在 Odoo 16 中配置搜索视图、过滤器和分组

Odoo 中有多种视图类型&#xff0c;包括表单、看板、树、日历、Qweb、搜索等。与表单视图相比&#xff0c;搜索视图用于过滤其他视图的内容&#xff0c;而不是显示内容本身。这使得搜索视图与其他视图不同。表单视图仅包含一条记录&#xff0c;因此不需要搜索。 本文将详细介绍…

PointNet——源码调试(模型训练+可视化测试显示)

因为项目涉及到3D点云项目&#xff0c;故学习下PointNet这个用来处理点云的神经网络 论文的话&#xff0c;大致都看了下&#xff0c;网络结构有了一定的了解&#xff0c;本博文主要为了下载调试PointNet网络源码&#xff0c;训练和测试调通而已&#xff0c;不涉及后续的改进优化…

PHP项目中的前端页面随意点击卡片后会重定向到首页或登录页

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

判断对象能否回收的两种方法,以及JVM引用

判断对象能否回收的两种方法&#xff1a;引用计数算法&#xff0c;可达性分析算法 引用计数算法&#xff1a;给对象添加一个引用计数器&#xff0c;当该对象被其它对象引用时计数加一&#xff0c;引用失效时计数减一&#xff0c;计数为0时&#xff0c;可以回收。 特点&#xf…

STMCUBEMX_IIC_LL库/HAL库_扫描总线设备

STMCUBEMX_IIC_LL库/HAL库_扫描总线设备 前言&#xff1a; 在很多开发过程中&#xff0c;I2C总线上会挂载多个从机设备&#xff0c;但是又不知道设备的地址是多少&#xff0c;我做一个简单的小工具扫描总线&#xff0c;把地址打印出来就很方便 LL库实例&#xff1a; void scan…

欧姆龙安全PLC及周边产品要点指南

电气安全、自动化设备作业安全&#xff0c;向来是非常非常之重要的&#xff01;越来越多的客户在规划新产线、改造既有产线的过程中&#xff0c;明确要求设计方和施工方将安全考虑进整体方案中进行考虑和报价&#xff01;作为一名自动化电气工程师&#xff0c;尤其是高级工程师…

Python爬虫教程第3篇-解决使用reqeusts遇到的ProxyError异常

起因 问题出现在windows电脑上&#xff0c;我用mac执行程序的时候并不会报错&#xff0c;但是如果在windows上的时候&#xff0c;大部分windows电脑会报错&#xff0c;而有些版本低的windows电脑又不会报错。 异常栈信息 HTTPSConnectionPool, Cannot connect to proxy, no …

智能无人数字直播间 打造24小时的无人直播间源码系统 带网站的安装代码包以及搭建教程

系统概述 智能无人数字直播间系统是一种基于人工智能技术的软件工具&#xff0c;它结合了高精度扫描建模、自动化控制、多模态生成等多项先进技术&#xff0c;能够实现对真实人物的高度仿真&#xff0c;并自主执行各类直播任务。该系统不仅支持24小时不间断直播&#xff0c;还…

物联网安全的优秀实践以及八种策略

大多数物联网安全漏洞都是可以预防的&#xff0c;甚至可能是全部。看看任何引人注目的物联网攻击&#xff0c;都会发现一个已知的安全漏洞。 大多数物联网安全漏洞都是可以预防的&#xff0c;甚至可能是全部。看看任何引人注目的物联网攻击&#xff0c;都会发现一个已知的安全漏…

【BUG】RestTemplate发送Post请求后,响应中编码为gzip而导致的报错

BUG描述 20240613-09:59:59.062|INFO|null|810184|xxx|xxx||8|http-nio-xxx-exec-1|com.xxx.jim.xxx.XXXController.?.?|MSG接收到来自xxx的文件请求 headers:[host:"xxx", accept:"text/html,application/json,application/xhtmlxml,application/xml;q0.9,*…

如何在OpenFOAM的案例文件夹中确定数据的点和面,确定点和网格之间的关系,从而用于深度学习预测和构建模型呢(分析数据格式及其含义)

在OpenFOAM中&#xff0c;点&#xff08;points&#xff09;和面&#xff08;faces&#xff09;的定义是通过不同的文件来进行的。在案例一级目录下面的constant/polyMesh目录下&#xff0c;会有points, faces, owner, neighbour等文件&#xff0c;来描述网格的几何和拓扑结构。…

Vue学习笔记-自定义组件使用v-model

拆解实现 父组件 <template><div></div><Son :name"name" inputChange"inputChange"></Son>{{ name }} </template><script setup> import {ref} from vue import Son from ./son2.vueconst nameref("张…