深入探索分布式任务调度框架:MySQL实现高效锁机制

news2024/11/15 23:48:25

本文主要介绍项目中怎么使用 MySQL 实现分布式锁的

背景

假如我们现在要做一个高性能、可扩展的分布式任务调度框架,要怎么设计呢?下面是我之前自己设计的一个架构图。
分布式任务调度架构
为了方便后续的分布式锁的设计,我们大致描述下各个角色都做了哪些事情(这不是本篇文章的重点)

scheduler-client

做为一个 sdk,植入到各业务方系统,功能如下:

  • 定期注册心跳信息
  • 暴露 http 服务端口,监听 handler 请求

scheduler-web

与前端页面交互,保存任务调度信息

scheduler-trigger

该节点包含两个角色:masterslave

  • master:读任务表,分配任务
  • slave:按策略执行任务,调用 scheduler-client 的接口

分布式锁

从图中可以看到,scheduler-trigger分为了两个角色masterslave,那么角色是怎么确定的呢?就是通过去抢锁,谁抢到锁,谁就是 master

所以,重点就在于该怎么设计抢锁这个动作?

锁表设计

CREATE TABLE ` lock ` (
  ` id ` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  ` namespace ` varchar(128)  NOT NULL DEFAULT '' COMMENT '锁名',
  ` owner ` varchar(128) DEFAULT NULL COMMENT '资源所有者(ip地址)',
  ` version ` bigint(20) NOT NULL DEFAULT '0' COMMENT '版本号',
  ` create_time ` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  ` update_time ` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (` id `) USING BTREE,
  KEY ` idx_namespace ` (` namespace `) USING BTREE
) ENGINE = InnoDB  COMMENT = '锁信息表'

这就是基于 MySQL 的分布式锁表设计,其中namespace代表锁的名称,owner代表该锁被哪个 ip 节点所持有。

初始化锁

在系统启动的时候,我们需要去监听启动事件,然后去初始化锁信息。

@Component
public class LockerHandler implements ApplicationListener<ApplicationEvent> {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        try {
            if (event instanceof ApplicationStartedEvent) {
                //初始化锁
            }
        } catch (Exception e) {}
    }
}

初始化锁的逻辑就是insert 一条锁信息,只不过此时锁还未被任何 owner 所持有。

INSERT INTO lock(`namespace`,`version`,create_time, update_time) VALUE ('master',1,NOW(),NOW())

抢锁&锁续约

在系统启动几秒后,有一个定时任务,每秒钟执行一次。

@Scheduled(initialDelay = 5000,fixedDelay = 1000)
public void lock() {
    try {
        LockTypeEnum lt = lock("master", InetTool.LOCAL_IP, 3);
        /**
        这里面是抢锁之后的业务逻辑,暂且不表
        **/
        return;
    } catch (Exception e) {  
    }
}


@Override
public LockTypeEnum lock(String namespace, String owner, int ttl) {
    //查询锁
    LockDO lock = this.lockDao.get(namespace);
    //如果锁过期或者无人持有锁,则触发DB抢锁
    if (lock.isExpired(ttl)) {
        return this.lockDao.lock(namespace, owner, lock.getVersion()) ? LockTypeEnum.PROMOTED : LockTypeEnum.UNKNOWN;
    }
    //如果锁未过期,且持有者是自己,则续约
    if (owner.equals(lock.getOwner())) {
        return this.lockDao.keepAlive(namespace, owner, ttl) ? LockTypeEnum.STAY : LockTypeEnum.LEAVE;
    }
    return LockTypeEnum.UNKNOWN;
}

下面来详细解剖下里面的代码逻辑

查询锁

通过namespace去查询锁信息

SELECT *,
(UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time)) AS remaining
FROM lock
WHERE namespace = #{namespace}
LIMIT 1

remaining 代表当前时间与上一次keepAlive更新时间的差值,可用来判断锁是否过期。

判断触发抢锁的条件
//触发抢锁的条件 1.锁过期 2.无人持有锁
public boolean isExpired(int ttl) {
    return remaining - ttl > 0 || owner == null;
}

remaining > ttl 代表已经超过 3秒没有更新了,满足该条件或owner 为空,会触发抢锁。

抢锁
UPDATE lock
SET
    update_time = NOW(),
    owner = #{owner},
    `version` = `version` + 1
WHERE `namespace` = #{namespace} 
AND `version` = #{version}

抢锁涉及到并发操作,所以采用了版本号的方式来保证安全性

锁续约

如果锁未过期且持有者是自己,触发锁续约

UPDATE lock
SET
update_time = NOW()
WHERE namespace = #{namespace} 
AND owner = #{owner} 
AND update_time >= DATE_SUB(NOW(),INTERVAL 3 SECOND)

此处的where判断条件也再次校验了,update_time >= 当前时间 - 3秒,代表锁还没有过期。

总结

以上就是基于 MySQL 实现锁机制的流程,至于抢到锁后的 master 和 slaver 怎么去执行业务逻辑,那又是另一件事情了,后面再单独说。

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

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

相关文章

搭建springboot项目,并解决项目出现红色J问题

搭建springboot的2种方式 搭建springboot项目有多种方式&#xff0c;这里简单介绍2种&#xff0c;看您使用哪个更方便。 第一种&#xff1a;在idea里创建 第二种&#xff0c;在官网创建下载 spring官网地址&#xff1a;https://start.spring.io/ 解决项目出现红J问题 搭建好…

【OpenHarmony】openharmony移植到RK3568------获取源码编译OpenHarmony源码

一、源码获取 源码获取有好几种方式&#xff0c;在这里直接在镜像网站下载源码&#xff0c;点击下面连接下载全量版本的OpenHarmony4.1 https://repo.huaweicloud.com/openharmony/os/4.1-Release/code-v4.1-Release.tar.gz 将源码放到自己建立的目录下解压&#xff0c;我放…

[JavaEE] 工作流- Activiti7 框架详解

目录 1、Activiti介绍 1.1、BPMN设计器 1.2、常见流程符号 1.2.1、事件event 1.2.2、活动activiti 1.2.3、流向flow 2、入门案例 2.1、需求说明 2.2、初始环境 2.2.1、添加依赖 2.2.2、添加配置 2.2.3、添加引导类 2.2.4、启动项目 2.2.5、表结构 2.2.6、常见ap…

【解析几何笔记】5.仿射坐标系与二阶行列式

5.仿射坐标系与二阶行列式 5.1 定义 【定义1.2】空间中一点 O O O与三个不共面向量 e 1 , e 2 , e 3 \pmb{e}_{1},\pmb{e}_{2},\pmb{e}_{3} e1​,e2​,e3​一起构成空间的一个仿射标架&#xff0c;记作 [ O ; e 1 , e 2 , e 3 ] [O;\pmb{e}_{1},\pmb{e}_{2},\pmb{e}_{3}] [O;…

Android CCodec Codec2 (三)C2Param - Ⅰ

在Codec2框架中&#xff0c;对组件的配置&#xff08;Setting&#xff09;、微调&#xff08;Tuning&#xff09;以及组件回传的信息&#xff08;Info&#xff09;都是通过参数的形式进行传递的。无论是简单参数&#xff08;只包含一个值&#xff09;还是复杂参数&#xff08;包…

HEIC批量格式转化JPG怎么转?这四种方法很好用

HEIC批量格式转化JPG怎么转&#xff1f;随着智能手机技术的不断发展&#xff0c;HEIC&#xff08;High Efficiency Image Container&#xff09;作为一种高效的图像压缩格式&#xff0c;逐渐被广泛应用于iOS设备中。然而&#xff0c;由于HEIC格式的兼容性问题&#xff0c;许多非…

Echarts 散点图的 tooltip 自定义formatter方法(展示X、Y、value之外的数据)

1.效果展示&#xff0c;如图&#xff0c;tooltip的构成是指标名实际值【目标值】 2.后端的数据结构 3.完整代码&#xff1a;主要就是将需要展示的字段数据拼好放到tooltipInfo里 initLeftEcharts() {const now new Date();const year now.getFullYear();const month …

oracle共享池(shared pool):一、工作原理、组成部分 二、软硬解析过程

文章目录 oracle整体结构图共享池&#xff08;shared pool&#xff09;shared pool的作用shared pool的组成查询 shared pool 各组成部分大小硬解析和软解析 oracle整体结构图 共享池&#xff08;shared pool&#xff09; shared pool的作用 1、 将 sql 语句解析成执行计划 …

统一服务入口-Gateway(一)

目录 1.网关介绍 1.1含有问题 1.2什么是API网关 网关核心功能&#xff1a; 2.Spring Cloud Gateway 2.1什么是Spring Cloud Gateway 2.2快速上手 2.2.1创建网关项目 2.2.2引入网关依赖 2.2.3添加Gateway的路由配置 2.2.4测试 2.3Predicate 2.3.1Predicate的其他写…

[数据集][目标检测]电力场景红外图像输电线路绝缘子检测数据集VOC+YOLO格式1846张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1846 标注数量(xml文件个数)&#xff1a;1846 标注数量(txt文件个数)&#xff1a;1846 标注…

《大模型应用开发极简入门》-当有了一个大模型,你需要知道的几件事情

从某种意义上来说&#xff0c;大模型&#xff08;LLM-Large language model&#xff09;也是一个任人打扮的小姑娘&#xff0c;你可以对她进行课程教学&#xff08;即微调&#xff09;、可以告诉她一些问题的应对办法&#xff08;即提示工程&#xff09;、还可以带上一部计算器…

(2024,ReLU-Transformer,样条,Veronese 映射,Pierce–Birkhoff 猜想)注意力机制是平滑的三次样条

Attention is a smoothed cubic spline 目录 0. 摘要和简介 0.1. 通过样条理解 Transformer 1. Transformer 的数学描述 1.9. ReLU-Transformer 2. 样条&#xff08;Spline&#xff09; 2.1. 标量值样条 2.2. 向量值样条 2.3. 矩阵值样条 2.4. Pierce–Birkhoff 猜想…

大杂烩!注意力机制+时空特征融合!组合模型集成学习预测!CNN-LSTM-Attention-Adaboost多变量负荷预测

大杂烩&#xff01;注意力机制时空特征融合&#xff01;组合模型集成学习预测&#xff01;CNN-LSTM-Attention-Adaboost多变量负荷预测 目录 大杂烩&#xff01;注意力机制时空特征融合&#xff01;组合模型集成学习预测&#xff01;CNN-LSTM-Attention-Adaboost多变量负荷预测…

AI大模型开发——7.百度千帆大模型调用

本节旨在为读者提供一个实用指南&#xff0c;探讨如何有效地利用百度千帆大模型平台的强大功能。从基础的账号注册和密钥申请入手&#xff0c;逐步引领用户通过案例&#xff0c; 理解并掌握如何调用文本和图像处理的大模型 API&#xff0c; 包括但不限于 NLP、对话生成、文本续…

linux中对.jar文件的配置文件进行修改

linux中对.jar文件的配置文件进行修改 第一步&#xff0c;进入你的.jar的当前文件夹 第二步 &#xff0c;编辑你指定的 .jar 文件 编辑之前请先备份 cp xxx.jar xxx-1.2.jar 输入编辑命令 vim xxx.jar第三步&#xff0c;找到你要编辑的文件 输入命令进入vi模式&#xff08;…

Python(TensorFlow)多模光纤光束算法和GPU并行模拟

&#x1f3af;要点 &#x1f3af;多模光纤包含光学系统线性和非线性部分 | &#x1f3af;单变量线性回归、多变量线性回归、人脸图像年龄预测、音频语音分类和 X 射线图像评估算法 | &#x1f3af;在空间光调制器记录海螺参数矩阵&#xff0c;光束算法多变量预测年龄 | &#…

pytorch训练后pt模型中保存内容详解(yolov8n.pt为例)

在 PyTorch 中&#xff0c;.pt 模型文件通常包含以下几类数据&#xff1a; 模型参数&#xff1a; 存储模型的权重和偏置参数。 优化器状态&#xff1a; 包含优化器的状态信息&#xff0c;以便在恢复训练时能够从中断的地方继续。 训练状态&#xff1a; 一些训练过程中的信息&am…

SpringBoot的自动配置原理探究

目录 什么是SpringBoot的自动配置&#xff08;Auto-Configuration&#xff09; 举例&#xff1a;SpringBoot自动配置&#xff08;Redis的自动配置&#xff09;的实例&#xff1a; 步骤1.&#xff1a;引入Redis启动器pom依赖 步骤2.在application.yml或者&#xff08;proper…

火狐浏览器应用商店不支持下载

前言 之前手机一直用的火狐浏览器&#xff0c;现在换了新的手机&#xff0c;又想下载使用&#xff0c;从官网直接下载现在直接跳载到Google Play才能下载&#xff0c;但是国内又用不了的&#xff0c;这里就记录一下怎么在手机应用商店不支持情况下载。 从FTP服务器下载Beta版…

C++学习笔记----4、用C++进行程序设计(四)---- 复合关系与继承关系之间的细线

在现实世界只是很容易区分对象之间是复合关系还是继承关系。没有人会说桔子有一个水果--而只能是桔子是一种水果。但是&#xff0c;在代码中&#xff0c;有时候就不是那么清晰了。 设想有一个代表关联数组的假想类&#xff0c;将一个键影射到一个值的数据结构。例如&#xff0c…