多台服务器分布式定时调度的几种方案

news2024/10/23 15:19:43

背景:现在有多个后端服务器,并且在代码中定义了一个定时任务,希望这个定时任务在一个时间只在一个服务器上执行,涉及到分布式调度,调研了一下总结出几种方案:

1.mysql的内置GET_LOCK

GET_LOCK方法的介绍
GET_LOCK是MySQL提供的一种加锁机制,用于控制并发访问数据库中的资源。GET_LOCK允许一个客户端获取一个带有给定名称的锁,并且只有该客户端能够释放该锁。这个锁是应用程序级别的,在不同的mysql会话之间使用,是名字锁,不是锁具体某个表名或字段,具体是锁什么完全交给应用程序。它是一种独占锁,意味着哪个会话持有这个锁,其他会话尝试拿这个锁的时候都会失败。这种方式是针对锁内的所有操作加锁,并不针对特定表或特定行,如果不释放锁,直到关闭连接会话结束,锁才会释放

以下是GET_LOCK方法的语法:

select GET_LOCK(str, timeout);
str: 锁的名称,通常是一个字符串。
timeout: 获取锁的超时时间(秒),如果在指定的时间内无法获取到锁,GET_LOCK将返回0。

释放锁:SELECT RELEASE_LOCK(@lock_key);
在这里插入图片描述
如果使用java的jpa,直接定义一个方法,用原生的sql即可,并且不用指定表

   @Query(value = "SELECT GET_LOCK(:lockName, 10)", nativeQuery = true)
    int addLock(@Param("lockName") String lock);

    @Query(value = "SELECT RELEASE_LOCK(:lockName)", nativeQuery = true)
    int releaseLock(@Param("lockName") String lock);

2.version乐观锁

需要在数据库表中增加一个version字段,主要用于实现并发更新,读取数据时,将version字段值一通取出,每更新一次version加一,提交更新时判断当前version与第一次取出来的version是否相等,相等则更新,否则认为是过期数据。如下图所示:
在这里插入图片描述

使用:

先查出出记录

select (status,status,version) from t_goods where id=#{id}

再修改记录

update t_goods

set status=2,version=version+1

where id=#{id} and version=#{version};

如果使用jpa,可以直接使用version注解来标识版本号字段:

  @Version
    private int version;  // 版本号字段

此时当尝试更新实体时,Spring Data JPA会自动检查版本号是否一致。

3.mysql的悲观锁

用for update实现,sql语句层面是这样:

update table set column=‘value’ for update

这种情况where条件如果涉及到数据库对应的索引字段,会是行级锁,否则会是表锁

实现悲观锁的时候有两种方式:
自行写原生SQL,然后写上for update语句。(方法:findCatalogsForUpdate)
使用@Lock注解,并且设置值为LockModeType.PESSIMISTIC_WRITE即可代表行级锁。

使用Lock注解例子:

@Lock(value = LockModeType.PESSIMISTIC_WRITE) //代表行级锁
    @Query("select a from Catalog a where a.id = :id")

    Optional<Catalog> findCatalogWithPessimisticLock(@Param("id") Long id);


当你使用 @Lock(LockModeType.PESSIMISTIC_WRITE) 注解来加锁查询结果时,查询会获取一个写锁(排他锁)。这意味着在当前事务提交之前,其他事务将无法读取或修改被锁定的行。

缺点:使用Lock加锁,由于mysql执行速度很快,在一台节点上执行完之后会很快释放锁,另外的节点进入时仍然会获取到锁

4.redis分布式锁

boolean acquired = redisLock.tryLock(LOCK_KEY, lockValue, LOCK_TIMEOUT, TimeUnit.SECONDS); 

if (acquired) {}

这里在使用时为了防止多台节点先后得到锁,可以设置redis自动过期机制:

 //如果键不存在则新增,存在则不改变已经有的值。(备注:失效时间要大于多台服务器之间的时间差,如果多台服务器时间差大于超时时间,定时任务可能会执行多次)

 Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, value, 20, TimeUnit.SECONDS);

if (flag != null && flag) {

 log.info("{} 锁定成功,开始处理业务", key)

            }

5.分布式任务调度框架(quartz\XXL-JOB)

Quartz 是一个开源的任务调度框架,支持以下功能:

简单和复杂的调度:支持简单的时间间隔调度和复杂的 Cron 表达式调度。

持久化:支持将调度信息持久化到数据库中,确保任务在应用重启后依然有效。

集群支持:支持在分布式环境中运行,确保任务在多个节点中只执行一次。

灵活的任务定义:支持定义各种类型的任务,包括无状态和有状态任务。

缺点:使用来说相对需要加的东西较多,需要添加新依赖和新的类:

Quartz 的基本概念

Job:任务接口,定义具体的任务逻辑。

JobDetail:任务详情,包含任务的定义和相关数据。

Trigger:触发器,定义任务的触发时间和频率。

Scheduler:调度器,管理和调度任务。

Quartz 的使用

  1. 添加依赖

在 Maven 项目中添加 Quartz 依赖:

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>
  1. 定义任务

实现 Job 接口,定义具体的任务逻辑:

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Executing MyJob at " + System.currentTimeMillis());
    }
}

XXL-JOB:

同样需要添加新的依赖,并且要引入xxljob的配置:

<dependency>
  <groupId>com.xuxueli</groupId>
  <artifactId>xxl-job-core</artifactId>
  <version>2.3.0</version>
</dependency>

配置:

@Configuration
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
    
    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;
    @Value("${xxl.job.accessToken}")
    private String accessToken;
    @Value("${xxl.job.executor.appname}")
    private String appname;
    @Value("${xxl.job.executor.address}")
    private String address;
    @Value("${xxl.job.executor.ip}")
    private String ip;
    @Value("${xxl.job.executor.port}")
    private int port;
    @Value("${xxl.job.executor.logpath}")
    private String logPath;
    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;
    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        return xxlJobSpringExecutor;
    }
}

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

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

相关文章

【学术会议-1】携手共创新纪元:加入2024年11月计算机科学与技术学术会议,探索前沿科技,分享智慧,共同塑造未来!

【学术会议-1】携手共创新纪元&#xff1a;加入2024年11月计算机科学与技术学术会议&#xff0c;探索前沿科技&#xff0c;分享智慧&#xff0c;共同塑造未来&#xff01; 【学术会议-1】携手共创新纪元&#xff1a;加入2024年11月计算机科学与技术学术会议&#xff0c;探索前…

【C++】创建TCP客户端

目录 一、实现发送字符串功能 二、实现接收字符串功能 三、客户端接收乱码问题 四、客户端发送乱码问题 五、客户端接收到数据时进行回调 六、子线程接收数据 七、发送Json格式数据 源码 一、实现发送字符串功能 头文件 #pragma once #include <iostream> #inc…

快速体验 Spring AI_ 绘图样例_Spring AI alibaba

Spring AI : 一套面向java开发者的大模型统一接口 过去&#xff0c;用Java开发AI应用时面临的主要困境是缺乏统一标准的封装库&#xff0c;导致开发者需针对不同AI服务提供商&#xff08;如OpenAI、阿里云等&#xff09;各自独立对接接口文档&#xff0c;增加了学习成本与迁移…

Labview创建FPGA项目异常解决

安装了FPGA模块后&#xff0c;无法在没有真实FPGA模块时&#xff0c;创建FPGA项目。 此时需要安装多个驱动后可以解决该问题。

【帕鲁杯应急响应WP】

文章目录 一、序言 二、背景信息 三、网络拓扑 四、资产清单 五、应急响应题目 一、序言 也是终于把帕鲁杯应急响应完整做一遍了&#xff0c;主办单位真用心了&#xff0c;这么大环境&#xff0c;总结下来还是很有收获&#xff0c;但是毕竟是做题有时候不知道出题人意图不…

mitmproxy安装以及使用

mitmproxy 是一个强大的中间人代理工具&#xff0c;可以用来拦截、查看、修改HTTP/HTTPS流量。它对于测试应用程序、分析网络请求、安全审计等场景非常有用。以下是 mitmproxy 的安装和基本使用流程。 在 Linux 和 macOS 上安装 确保已安装 Python&#xff1a;mitmproxy 需要 P…

技术干货|企业如何通过创建可持续能源的数字孪生,实现即时洞察

主要看点 行业&#xff1a;能源 挑战&#xff1a;聚变动力装置在设计评估阶段需要复杂的数字仿真模型。能源企业通常希望利用昂贵的设计模型&#xff0c;通过输入从电厂现场实时传感器数据来创建数字孪生模型&#xff0c;从而帮助工程师了解电厂的结构完整性&#xff0c;并进一…

李德仁院士携实验室及大势文旅团队参加“湖北旅游、武当突破”名家谈,分享数智文旅发展新经验

10月12日上午&#xff0c;2024世界武当太极大会在湖北省十堰市武当山盛大开幕。 2023年国家科学技术最高奖获得者、中国科学院、中国工程院院士、武汉大学李德仁教授携测绘遥感信息工程国家重点实验室&#xff08;后简称“实验室”&#xff09;团队以及大势智慧文旅团队&#…

线性层(全连接层)pytorch

**前置知识&#xff1a; 1、线性层和非线性激活函数&#xff1a; 组合使用&#xff1a;通常&#xff0c;线性层后面会接一个非线性激活函数。这样&#xff0c;网络先做一次简单的转换&#xff08;线性&#xff09;&#xff0c;然后用激活函数&#xff08;非线性&#xff09;添…

迈巴赫S480升级原厂魔毯悬挂功能有哪些作用

迈巴赫 S480 升级魔毯空气悬挂系统的功能介绍如下&#xff1a; 1. 平稳驾驶体验&#xff1a; • 路况适应&#xff1a;通过摄像头和雷达扫描车前方路面状况&#xff0c;提前获取路况信息&#xff0c;然后根据这些信息自动调节空气悬挂的软硬程度。无论是在平坦的高速公路&…

最新Spring Boot3框架入门教程,基础知识讲解(参考官方文档),同时基于MybatisPlus+MYSQL搭建后台管理系统基础流程(附源码)

本文所涉及的代码以及相关文件均上传至仓库:GitHub - yang66-hash/XDPropertyManagementSystemDemo: This is a demo template based on SpringBoot3 in the background of property management system. Spring Boot 是由 Pivotal 团队开发的一款开源框架&#xff0c;它可以帮助…

如何防止箱包发霉 工厂箱包防霉方案

工厂储存的皮具、箱包保存和防护是一个很重要的问题。尤其是在潮湿多雨的季节&#xff0c;很容易受到霉菌侵袭。那么&#xff0c;如何在不损害品质的前提下&#xff0c;实现其长期保存而不发霉呢?经ihaoer防霉人士介绍箱包发霉处理方法和防霉方法如下&#xff1a; 箱包发霉处理…

JavaScript 字符串魔法:实用技巧——WEB开发系列45

这篇文章&#xff0c;探讨一下 JavaScript 中的字符串操作。字符串是编程中的基本数据类型之一&#xff0c;它们无处不在&#xff0c;几乎在所有的代码中都需要处理。了解字符串的基础知识、常用的内置方法&#xff0c;通过实例来学习高效地操作字符串。 一、什么是字符串&…

史上最好用的html类word编辑器

前言 近期在做一个项目&#xff0c;需要用到大量的word模板生成对应资料还要打印&#xff0c;之前想的是用一款富文本编辑器即可使用&#xff0c;无赖客户比较刁钻要求系统中看到的所有页面尽量和word上效果一样&#xff0c;并且打印出来每一页内容和系统显示的要一致&#xf…

如何根据店铺商品选择合适的礼品代发平台?

随着电商行业的蓬勃发展&#xff0c;礼品代发服务已经成为很多店铺提升客户体验、增加订单量的重要策略。尤其是对于那些想要通过赠送小礼品、促销品或节日礼物来吸引顾客的商家来说&#xff0c;选择一个合适的礼品代发平台至关重要。如何根据店铺的商品特点选择一个最适合自己…

人员跌倒检测系统的设计与实现(Yolov Python38 深度学习)+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

数据结构与算法——Java实现 35.求数据流中的第K大元素

目录 703. 数据流中的第 K 大元素 思路 题目解析&#xff1a; 数据流&#xff1a; 数据流和数组的区别&#xff1a; 代码实现 小顶堆类 测试类 力扣 我想成为一个强大、坦荡又热血的人&#xff0c;我爱霓虹闪烁&#xff0c;也爱高山流水&#xff0c;更爱我自己 —— 24.10.13 7…

视频的编解码格式

文章目录 视频的编解码格式概念术语视频处理流程视频封装格式视频编码格式视频编解码器&#xff0c;视频容器和视频文件格式之间的区别补充视频码率 参考资料 视频的编解码格式 概念术语 两大组织主导视频压缩的组织及其联合(joint)组织 ITU-T(VCEG) ITU-T的中文名称是国际电信…

【wpf】05 几种容器动态创建控件的对比

今天利用一点时间&#xff0c;对wpf中在常用容器中动态创建控件的方法进行了学习和测试&#xff0c;本篇文章用来记录这个过程及一些心得。 1 容器说明 用于对比的wpf常用容器类包括如下七种&#xff1a; StackPanelGridScrollViewerWrapPanelCanvasUniformGridDockPanel 以…

Vue实现动态表单

使用 Vue 实现动态表单 在前端开发中&#xff0c;我们经常遇到根据用户输入动态生成不同表单项的需求。这类动态表单不仅提升了用户体验&#xff0c;还可以让复杂的交互流程变得简洁而高效。本文将详细讲解如何使用 Vue 3 的响应式特性&#xff0c;逐步构建一个递归动态表单。…