实现分布式锁

news2024/9/20 16:58:58

背景

分布式锁是一种用于协调分布式系统中多个节点之间并发访问共享资源的机制。在分布式系统中,由于存在多个节点同时访问共享资源的可能性,需要使用分布式锁来保证数据的一致性和正确性。

今天要实现的是分布式场景中的互斥类型的锁。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下面时分布式锁的实现重点
在这里插入图片描述

借助MySQL实现

主要利用MySQL唯一键和唯一性约束来实现互斥性

表结构

DROP TABLE IF EXISTS `dislock`;

CREATE TABLE `dislock` (
		  `id` int(11) unsigned NOT NULL AUTO_INCREMENT	COMMENT '主键',
		  `lock_type` varchar(64) NOT NULL COMMENT '锁类型',
		  `owner_id` varchar(255) NOT NULL COMMENT '持锁对象',
		  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
		  PRIMARY KEY (`id`),
		  UNIQUE KEY `idx_lock_type` (`lock_type`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='分布式锁表';

创建一个名为dislock的表,用于存储分布式锁的信息。该表包含以下字段:

  • id:主键,自增长的整数类型。
  • lock_type:锁类型,字符串类型,用于标识锁的类型。
  • owner_id:持锁对象,字符串类型,用于标识持有锁的客户端或其他相关信息。
  • update_time:更新时间,时间戳类型,表示最后一次更新该行数据的时间。

在上面的SQL语句中,idx_lock_type是一个唯一索引,它定义在lock_type字段上,确保表中不会有两个相同的lock_type值。这样可以保证同一类型的锁在表中只有一条记录,避免了同一客户端重复获取锁的情况。

加锁和解锁

INSERT INTO dislock (`lock_type`, `owner_id`) VALUES ('act_lock', 'ad2daf3');
DELETE FROM dislock WHERE `lock_type` = 'act_lock' AND `owner_id` = 'ad2daf3'; // 要确保谁加锁谁解锁

如果要用MySQL实现的话,**还需要开一个进程(要求计算型高可用),来管理超时,**不断去查询updatetime,如果该锁超过了最长允许存在的时间,则需要删除数据库对应的该行。

如果要实现可重入的话,那么考虑再增加一个数据库字段来实现。

借助Redis实现

在Redis中,可以使用SET命令来实现分布式锁。具体实现方法如下:

  1. 使用SET命令尝试在Redis中设置一个键,例如lock:resource,并将其值设置为一个唯一的标识符,例如当前进程的ID或一个随机字符串。可以使用NX选项来确保只有在该键不存在时才进行设置,从而实现加锁操作。

  2. 如果SET命令返回了OK,则说明该键被成功设置,当前进程获得了锁;否则,说明该键已经被其他进程持有,当前进程没有获得锁,需要等待一段时间后重试。

  3. 在完成操作后,使用DEL命令删除该键,释放锁。

需要注意的是,在使用SET命令设置键的值时,应该设置一个过期时间,以防止锁被持有进程意外终止而无法释放。可以使用EX选项来设置过期时间,例如SET lock:resource <identifier> EX 10表示将锁的过期时间设置为10秒。

另外,为了避免锁的误删除,应该使用与设置键的标识符不同的值来删除锁。可以使用Lua脚本来实现原子性的加锁和解锁操作,从而避免并发问题。例如,下面是一个简单的Lua脚本,实现了基本的加锁和解锁操作:

-- 加锁操作
if redis.call('SET', KEYS[1], ARGV[1], 'EX', ARGV[2], 'NX') then
    return 1
else
    return 0
end

-- 解锁操作
if redis.call('GET', KEYS[1]) == ARGV[1] then
    return redis.call('DEL', KEYS[1])
else
    return 0
end

我们今天主要考虑下面的方法
当使用 Redis 的 Redlock 算法时,需要考虑以下关键步骤和注意事项:

  1. 选择 N 个 Redis 实例

    • 选择的 Redis 实例应该分布在不同的物理服务器或者逻辑节点上,以确保它们不会受到单点故障的影响。
    • 这些实例可以是独立的 Redis 节点,也可以是 Redis 集群中的节点。
  2. 获取当前时间

    • 在进行锁操作之前,首先需要获取一个精确的当前时间戳。这可以通过系统时间或者某种网络时间协议(如NTP)来获得。
  3. 尝试在每个实例上获取锁

    • 对于每个选定的 Redis 实例,使用相同的锁键和唯一的随机值(例如 UUID)执行 SET 操作,并设置适当的超时时间和标识符,以确保只有持有锁的客户端才能释放锁。
    • 设置锁的超时时间是为了避免锁被永久性地持有,即使持有锁的客户端出现故障。
  4. 计算获取锁所需的时间

    • 计算获取锁所需的时间,主要包括获取锁的时间、网络延迟以及时钟漂移等。这些因素都会影响锁的有效性。
  5. 判断是否成功获取锁

    • 如果大多数实例(至少超过半数)成功获取了锁,并且用于获取锁的时间没有超过超时时间,则认为获取锁成功。
    • 如果无法获得大多数实例的支持,可能需要重试或者放弃锁操作。
  6. 释放锁

    • 在完成任务后,需要在所有实例上执行删除操作来释放锁。

注意事项

  • 网络分区:在面对网络分区时,需要考虑如何处理部分 Redis 实例无法通信的情况。这可能需要引入额外的逻辑来检测并处理这种情况。
  • 时钟漂移:由于不同的服务器上的时钟可能存在不同程度的漂移,需要谨慎处理时钟同步问题,以确保锁的超时时间计算准确。
  • Redis 实例故障:需要考虑 Redis 实例的故障处理,包括如何发现故障实例并采取适当的措施。

总之,实现 Redlock 算法需要综合考虑各种因素,并根据具体情况进行调整,以确保系统在分布式环境下能够正确、高效地运行。

代码实现参考:
链接: https://github.com/jacket-code/redlock-cpp

其他的方法未完待续,后续补充

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

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

相关文章

免费使用IntelliJ IDEA的7种方式(2024 最新版)

大家好&#xff0c;我是小黑&#xff0c;今天要和大家分享的是如何免费使用 IntelliJ IDEA。我们都知道&#xff0c;作为一名程序员&#xff0c;拥有一个高效的开发工具是至关重要的。IntelliJ IDEA 无疑是市面上最受欢迎的开发工具之一。但是&#xff0c;获取授权的成本有时会…

MySQL 索引(下)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL-进阶篇 &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现…

leetcode下一个更大的元素---1暴力---2单调栈

1.题目&#xff1a; nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。 给你两个 没有重复元素 的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#xff0c;其中nums1 是 nums2 的子集。 对于每个 0 < i < nums1.l…

STL中的map

概述 std::map 是一个模板类&#xff0c;定义在头文件 <map> 中&#xff1a; template<class Key,class T,class Compare std::less<Key>,class Allocator std::allocator<std::pair<const Key, T>> > class map;std::map 是一种有序关联容器…

考研C语言刷编程题篇之分支循环结构基础篇(一)

目录 第一题 第二题 方法一&#xff1a;要循环两次&#xff0c;一次求阶乘&#xff0c;一次求和。 注意&#xff1a;在求和时&#xff0c;如果不将sum每次求和的初始值置为1&#xff0c;那么求和就会重复。 方法二&#xff1a; 第三题 方法一&#xff1a;用数组遍历的思想…

redis-exporter grafana面板配置

一、前言 关于使用tensuns自带的grafana监控模板&#xff0c;监控redis-exporter接口会有一些数据丢失的问题&#xff0c;需要自行修改一下grafana模板的json 二、修改模板 redis grafana模板id&#xff1a;17507 主要是针对cpu使用率和内存使用率做一个说明&#xff0c;因为…

mac 中vscode设置root启动

1. 找到你的vscode app&#xff0c;点击鼠标右键------->选项----->在访达中显示 2. 终端中输入以下命令&#xff0c;不要点回车&#xff0c;不要点回车&#xff0c;输入一个空格 sudo chflags uchg 3. 然后将你的程序拖到终端&#xff0c;会自动…

智能光栅光片显微成像技术的LabVIEW解决方案

智能光栅光片显微成像技术的LabVIEW解决方案 在生物医学研究中&#xff0c;高效的成像技术对于捕捉细胞内罕见和复杂事件至关重要。智能光栅光片显微技术&#xff08;smartLLSM&#xff09;的出现&#xff0c;代表了LabVIEW软件在高端成像领域的革命性应用&#xff0c;这项技术…

Mac M1 Parallels CentOS7.9 Deploy Typecho

一、创建名称空间 kubectl create ns prod二、创建PV & PVC vim local-pv1.yamlapiVersion: v1 kind: PersistentVolume metadata:name: local-pv-1 spec:capacity:storage: 1GiaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: RetainstorageClassName: loca…

Selenium WebDriver与RC的差异

什么是Selenium WebDriver&#xff1f; Selenium WebDriver 是用于测试Web应用程序的API的开源集合。Selenium WebDriver工具&#xff0c;它还允许执行跨浏览器测试。 WebDriver还能够使用编程语言在创建测试脚本时使用。现在可以使用条件运算就像If-Then-Else或Switch-Case。…

Centos 7 单机部署 consul

一、下载安装 参考官网文档 Install | Consul | HashiCorp Developer 进入Centos 执行下面命令 sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo sudo yum -y install consul 这种方法安装完成…

linux下vsc的自动切换输入法解决方案

前言 个人使用的是Linux开发加上vsc编辑器&#xff0c;这两个东西一加中国开发者大致上就消失不见了&#xff0c;眼馋idea那个Smartinput很久了&#xff0c;赶上放假了&#xff0c;有空搞搞&#xff0c;如果后期有心情会做的通用点 安装 商店搜索SmartInputLinux安装 使用…

STM32标准库开发—MPU6050详细介绍

MPU6050简介 3轴IMU即只有3轴陀螺仪的IMU&#xff0c;其因为只有一个3轴陀螺仪&#xff0c;所以只能感知载体roll&#xff08;滚转&#xff09;、pitch&#xff08;俯仰&#xff09;、yawl&#xff08;偏航&#xff09;共3个自由度的姿态信息。 6轴IMU在3轴IMU的基础上加装了3轴…

Unity之射线检测

不知道大家有没有玩过红色警戒 —— 一款即时战略游戏&#xff0c;和罪恶都市一样小编小学的时候就开始玩了&#xff0c;这款游戏控制单位角色移动是通过鼠标的点击来实现。 同样的操作方法还有英雄联盟等很多游戏&#xff0c;那本篇文章小编就通过简单小实例来讲解这种操作在U…

[ComfyUI进阶教程] lcm+Lora+Controlnet工作流工作流

这是一个使用了LCMlora加载器CN&#xff08;depthtile&#xff09;的工作流。 工作流特性&#xff1a; LCM lora加载器&#xff0c;加快生成图片的时间。 配置了3个lora加载器&#xff0c;用来进行人物和风格设定。 提示词编辑器&#xff0c;预制了默认的动态提示词。 使用了…

linux第一个小程序 --- 进度条【简洁】

行缓冲区的概念 结果&#xff1a;先输入hello world然后休眠三秒后结束 当去掉’\n“ 后&#xff0c;结果就变成了先休眠三秒&#xff0c;然后打印hello world后结束。 该现象就证明了缓冲区的存在。 当缓冲区中遇到’‘\n’或者缓冲区被写满后才会被打印出来&#xff0c;在第…

【设计模式】腾讯二面:自动贩卖机/音频播放器使用了什么设计模式?

状态模式是什么&#xff1f; 状态模式&#xff0c;也被称作状态对象模式&#xff0c;是一种行为设计模式。 当一个对象的内在状态改变时&#xff0c;允许改变其行为&#xff0c;这个对象看起来像是改变了其类。 它让对象在其内部状态改变时改变自己的行为。外部调用者无需了…

(蓝桥杯每日一题)love

问题描述 马上就要到七夕情人节了&#xff0c;小蓝在这天想要心爱得男神表白&#xff0c;于是她写下了一个长度为n仅由小写字母组成的字符串。 她想要使这个字符串有 1314个 love 子序列但是马虎的小蓝却忘记了当前已经有多少个子序列为 love。 请你帮小蓝计算出当前字符串有多…

Rustdesk 中VP8 / VP9 / AV1 是什么?

环境&#xff1a; Rustdesk1.1.9 VP8 / VP9 / AV1 问题描述&#xff1a; VP8 / VP9 / AV1 是什么&#xff1f; 解决方案&#xff1a; 1.VP8、VP9和AV1是视频编解码器&#xff0c;用于压缩和解压缩视频数据。它们是由Google和Alliance for Open Media&#xff08;AOM&#…

spring springfox-swagger2 2.7.0配置

springboot版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.0.RELEASE</version><relativePath/> <!-- lookup parent from repository -->…