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

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

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注解来标识版本号字段:

  @Versionprivate 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 {@Overridepublic 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;@Beanpublic 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.rhkb.cn/news/447139.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP/IP相关

1、关于三次握手、四次挥手和TCP的11种状态&#xff1a; 记住这张图就行了&#xff1a; 2、关于慢启动、拥塞避免、超时重传、快速重传、快速恢复 记住这张图就行了&#xff1a; 一些名词解释&#xff1a; MSS&#xff1a;Maximum Segment Size&#xff0c;最大报文长度 RT…

[论文阅读]SCOTT: Self-Consistent Chain-of-Thought Distillation

中文译名&#xff1a;SCOTT: 思维链一致性蒸馏 会议&#xff1a;Proceedings of the 61st Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers) 链接&#xff1a;SCOTT: Self-Consistent Chain-of-Thought Distillation - ACL Antholo…

简单概述Ton链开发路径

区块链开发领域发展迅速&#xff0c;各种平台为开发人员提供不同的生态系统。其中一个更有趣且越来越相关的区块链是TON&#xff08;开放网络&#xff09;区块链。TON 区块链最初由 Telegram 构思&#xff0c;旨在提供快速、安全且可扩展的去中心化应用程序 (dApp)。凭借其独特…

CSS简单入门

一.简单概念 1.概念 层叠样式表&#xff0c;一种样式表语言&#xff0c;用来美化HTML文档的呈现。 2.书写位置 title标签下方添加style双标签&#xff0c;style标签里面书写CSS代码 &#xff08;1&#xff09;外部学习样式 <title>CSS使用</title> <sty…

【2022统考真题】计算时间复杂度

目录 一、题目描述 二、思路分析 三、易错提醒 四、同级和嵌套的关系 一、题目描述 下列程序段的时间复杂度是&#xff08;&#xff09; int sum 0; for (int i 1; i < n; i * 2) for (int j 0; j < i; j) sum; A. O(logn) B. O(n) C. O(nlogn) D…

前端转换double数据,保留两位小数

Number Number(1.00) 1 Number(1.10) 1.1 Number(1.101) 1.101 要想前端展示页面按 1.00展示1&#xff0c;1.10 展示1.1 需要套一个number() 1.1 保留两位小数&#xff0c;并三位一个分隔符 indexView.value[key] formatNumber(indexView.value[key].toFixed(2))//格式…

聚类分析 | WOA-K-means++聚类优化算法

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 (创新)WOA-K-means聚类优化算法 (WOA聚类优化&#xff0c;创新&#xff0c;独家) 鲸鱼算法优化K-means聚类优化算法 matlab语言&#xff0c;一键出图&#xff0c;直接运行 1.鲸鱼算法WOA作为群智能算法简单高效&a…

25.2 采集端高基数的现象和原因

本节重点介绍 : 什么是高基数采集端高基数的原因 标签的值过多 获取采集端的高基数metrics tsdb-status页面介绍统计原理讲解&#xff1a;是基于内存中的倒排索引 算最大堆取 top10通过接口获取metrics name top10 什么是高基数 通俗的说就是返回的series或者查询到的serie…

spring boot itext7 修改生成文档的作者、制作者、标题,并且读取相关的信息。

1、官方的example文件&#xff1a;iText GitHub itext-java-7.2.5\kernel\src\test\java\com\itextpdf\kernel\pdf\PdfStampingTest.java 2、修改代码&#xff1a; Testpublic void stamping1() throws IOException {String filename1 destinationFolder "stamping1_…

【安装教程】Windows10环境下Pytorch(GPU版)的安装与配置

目录 Pytorch的概念安装前要求一、NVIDIA驱动查看二、Anaconda的安装2.1 Anaconda的安装2.2 创建虚拟环境2.3 激活虚拟环境 三、CUDA ToolKit的安装&#xff08;选做&#xff0c;CPU版本可跳过&#xff09;3.1 CUDA安装包的下载&#xff08;以CUDA11.6.0为例&#xff09;3.2 CU…

【兼容多端】UNIAPP popper气泡弹层vue3+typescript unibest

最近要实习一个泡泡弹层。看了下市场的代码&#xff0c;要么写的不怎么好&#xff0c;要么过于复杂。于是拿个轮子自己加工。200行代码撸了个弹出层组件。兼容H5和APP和小程序。 功能&#xff1a; 1)只支持上下左右4个方向的弹层不支持侧边靠齐 2)不对屏幕边界适配 3)支持弹层…

EmEditor传奇脚本编辑器

主程序&#xff1a;EmEditor.exe 目前已有功能 可以自己指定一个快捷键 实现以下功能&#xff08;默认快捷键为&#xff1a;F1&#xff09; 以下全功能 都是鼠标所在行 按快捷键 &#xff08;默认快捷键&#xff1a;F1&#xff09; 1.在Merchant.txt中 一键打开NPC 没有…

注册安全分析报告:惠农网

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

C语言 | Leetcode C语言题解之第462题最小操作次数使数组元素相等II

题目&#xff1a; 题解&#xff1a; static inline void swap(int *a, int *b) {int c *a;*a *b;*b c; }static inline int partition(int *nums, int left, int right) {int x nums[right], i left - 1;for (int j left; j < right; j) {if (nums[j] < x) {swap(…

前端的AI工具:ChatGPT Canvas与Claude Artifacts对比 -仅仅是OpenAI一个迟来的追赶吗?- 贺星舰五飞试验成功

如果你对OpenAI的ChatGPT Canvas和Anthropic的Claude Artifacts有所耳闻&#xff0c;可能会想知道这两个工具有何不同&#xff0c;以及哪个能让你的工作流程更加顺畅。这两个工具旨在提升生产力&#xff0c;但侧重点各异——编码、写作、创意和实时反馈。 本文将深入探讨ChatG…

面腾讯后台开发,二面挂掉了,,,

随着各厂秋招的开启&#xff0c;收到面试邀请的同学也越来越多。在当年和我一起找实习的同学里面&#xff0c;有实力较强的同学收到了腾讯后台开发的校招面试邀请。但面试不止是实力的竞争&#xff0c;也有很重要的运气的因素。 虽然我的同学在腾讯后台开发的二面中挂掉了&…

76.最小覆盖子串

题目:76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 代码思路: (滑动窗口) O(n) 这道题要求我们返回字符串 s中包含字符串 t 的全部字符的最小窗口&#xff0c;我们利用滑动窗口的思想解决这个问题。因此我们需要两个哈希表&#xff0c;hs哈希表维护的是s字符串中…

QT:“提升为“使用(自定义控件)

目录 一.步骤与作用 1.步骤 2.作用 二.使用 1.mainwindow.ui ->拖一个 Push Button 控件到画布->右击Push Button弹出对话框->单击"提升为" 2.输入提升类名称MyButton->点击添加 3.选择基类名称为QPushButton,点击提升 4.新建MyButton文件 5.在…

初等数学几百年重大错误:将根本不是无穷集的真子集误为其真子集

黄小宁 【摘要】长为1的直线段形橡皮筋A拉长为长为2的橡皮筋B&#xff08;可二等分&#xff09;&#xff0c;去掉拉力使B缩短成原来的A&#xff0c;A不是B的一半。同样可证直线段L均匀压缩变短为直线段D&#xff5e;L不能成为L的一部分。数学一直误以为D是L的一部分使康脱推出…

《RabbitMQ篇》消费者轮询消费消息

当有多个消费者都在同一个队列中拿取消息时&#xff0c;会轮询从队列中拿取消息消费。 RabbitMQUtil类为工具类&#xff0c;获取Channel。 import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory;public…