Redis做分布式锁

news2024/11/19 2:46:43

(一)为什么要有分布式锁以及本质

  在一个分布式的系统中,会涉及到多个客户端访问同一个公共资源的问题,这时候我们就需要通过锁来做互斥控制,来避免类似于线程安全的问题

  因为我们学过的sychronized只能对线程加锁,在分布式系统中无法对进程进行加锁,此时我们就需要用分布式锁

 那分布式锁的本质我们可以理解为一个公共服务器,来记录加锁的状态,那我们这里使用redis来作为这个公共服务器

(二)分布式锁的基本实现

1.基础实现

  我们说分布式锁的本质是服务器,来记录加锁状态,那这个加锁的本质就是通过一个键值对的方式来标识锁的状态

  就用我们常见的购票场景,我们现在有多个服务器节点来提供购票需求,那购票的流程:先查询指定车的余票,如果余票>0,就-=1,很明显,这个操作不是原子的,就会导致有其他服务器节点插到中间执行,这就会导致超卖的情况(这种情况在单机上,我们可以通过对线程加锁的方式来处理,但是加锁对于多进程来说,是无能为力的)

  如果我们最终存储数据的服务器是mysql,我们可以使用事务来解决,但是如果不是,我们还是需要之后的步骤

  

 那我们这里想要加锁,我们就需要引入一个公共服务器,作为分布式锁的管理者

我们服务器节点会先访问redis,在redis设置一个键值对,比如key是车次

   如果这个操作设置成功,就视为有服务器节点对这个车次进行加锁了,其他的服务器节点想要购票时,就也需要写一个键值对,但是我们会发现这个key已经存在了此时就需要进行阻塞等待,等到我们加锁的这个服务器节点在进行完数据库的读写操作后,就要把redis刚才的键值对给删除掉,这个删除操作就相当于释放锁,然后我们其他的服务器节点才可以再次购票进行加锁解锁操作

 注:我们redis本来就是key-value结构,并且提供了setnx操作,当我们key不存在的时候就设置成功,存在就设置失败,所以使用redis很合适

2.引入过期时间

 当服务器1加锁后解锁前,如果服务器1挂了,就会导致我们这个解锁操作不能执行,那么其他的服务器程序就一直无法获取到锁

 那我们之前讲多线程的时候,使用了finally,来保证最后一定会解决,那这个能不能在分布式锁中使用呢?    是不可以的,因为我们加锁不是在自己进程中加的,而是在一个公共服务器中加的,程序异常退出,是不会给公共服务器上的锁解锁的

 那我们如果挂了,为了解决无法解锁的问题,不如我们未雨绸缪,我们在设置key的同时引入过期时间来保证这个key存在多久就自动销毁(这个锁加锁多久后自动解锁)

 那我们可以使用redis中的set ex nx的方式,在设置锁的同时设置过期时间

 注意:如果我们使用setnx 后使用expire,因为是两个指令,不是原子的,即使使用事务也不能保证都执行正确,就导致可能会出现无法正确释放锁的问题

3.引入校验id

   对于redis中的数据,我们其他服务器节点也是可以删除的,上述情况下,我们一个服务器对他加锁后,另一个服务器也可以进行解锁操作,虽然我们不会故意让另一个服务区程序去解锁,但是我们还是要保证不能因为一些bug导致服务器2把key误删了

  为了解决这个问题,我们可以把我们的服务器程序的编号给放到value中,因为我们上述说是写key然后校验key是否存在来判断是否加锁的,这个value的值就可以任我们发挥,那我们value放服务器编号,然后我们想要解锁时,先判断这个key对应的value是不是我们当前的服务器,如果是就进行删除,不是就不可以删除

那我们伪代码如下

 我们发现,这里的get和del不是原子的,那就可能会出现错误

  如果在多线程的情况下就会导致重复删除一个key,那有人会有疑问,重复删就删了呗,那如果此时正好有一个set key在最后一个del之前执行呢?这就会导致我们新设置的key被直接删除了

 那这里的问题我们可以使用redis事务来解决,也可以使用lua脚本

4.lua脚本

  lua是redis的一个内嵌语言,语法简单并且执行速度快,且轻量,并且redis官方文档说,我们可以使用lua来实现redis的事务

 因为redis执行lua脚本是相当于一个操作也就是原子的,但是lua脚本中可以有很多操作

如果使用lua脚本,那代码可以写为

5.引入watch dog

  上述方案还有一个问题,也就是我们过期时间的设置,我们设置了key过期时间后,可能会导致我们任务没执行完,key就过期了,或者当我们key过期时间很长,就会导致其他服务器无法及时加锁,那么针对这个问题,我们就引入了一个watch dog,本质上是加锁服务器上的一个单独线程,来针对这个加锁时间进行“续约”

 就比如,我们先设置过期时间1s,当还剩300ms我们任务没执行完,我们这个watch dog线程就会把过期时间重新设置,也就是续约过程,这样就不用担心过期时间设置的过长或者过短了,因为过期时间变成了动态的

 而且当我们服务器挂了,这个线程也就挂了,过期时间就不会改变,就可以正常的释放锁

6.引入redlock

我们上述都是在讨论服务器节点的问题,那假如我们redis服务器挂了呢?这时有人会说,主从结构和哨兵可以帮我们解决啊,我们一直会有主节点的,虽然是这样,但是会存在我们之前的主节点中有一些加锁操作没来得及同步数据给从节点,导致数据丢失,这样就相当于没有加锁,其他服务器就可以进行加锁

 那为了解决这种问题,redis作者提出了redlock算法

也就是引入了一组redis节点,每一组都是相同的主从结构,并且数据也相同,加锁的时候,我们按照一定顺序,写多个master节点,写操作时要设定操作的超时时间,当set key的操作超过超时时间没有成功,就视为加锁失败

   

  如果给某个节点加锁失败,就尝试下一个节点,当加锁成功的节点数超过总数一半,就视为加锁成功

 这个算法就是通过空间换取准确度

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

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

相关文章

阿里云引领智算集群网络架构的新一轮变革

阿里云引领智算集群网络架构的新一轮变革 云布道师 11 月 8 日~ 10 日在江苏张家港召开的 CCF ChinaNet(即中国网络大会)上,众多院士、教授和业界技术领袖齐聚一堂,畅谈网络未来的发展方向,聚焦智算集群网络的创新变…

预处理(1)(手绘)

大家好,今天给大家分享一下编译器预处理阶段,那么我们来看看。 上面是一些预处理阶段的知识,那么明天给大家讲讲宏吧。 今天分享就到这里,谢谢大家!!

ZYNQ程序固化——ZYNQ学习笔记7

一、ZYNQ启动过程 二、 SD卡启动实操 1、对ZYNQ进行配置添加Flash 2、添加SD卡 3、重新生成硬件信息 4、创建vitis工程文件 5、勾选板级支持包 6、对系统工程进行整体编译,生成两个Debug文件,如图所示。 7、插入SD卡,格式化为 8、考入BOOT.…

FPGA实现PCIE采集电脑端视频转SFP光口万兆UDP输出,基于XDMA+GTX架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案10G Ethernet Subsystem实现万兆以太网物理层方案 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图电脑端视频PCIE视频采集QT上位机XDMA配置及使用XDMA中断模块FDMA图像缓存UDP视频组包发送UDP协议栈MAC…

Mongo数据库集群搭建

目录 1、Mongo集群优势 1.1 高可用性 1.2 水平扩展性 1.3 高性能 1.4 灵活的架构设计 1.5 数据安全 1.6 管理与监控 2、下载指定操作系统版本包 3、部署和验证工作 3.1 准备配置文件及依赖 3.2 启动第一个节点 3.3 部署更多的节点 3.4 初始化副本集 3.5 设置管理…

创建vue3项目步骤

脚手架创建项目: pnpm create vue Cd 项目名称安装依赖:Pnpm iPnpm Lint:修复所有文件风格 ,不然eslint语法警告报错要双引号Pnpm dev启动项目 拦截错误代码提交到git仓库:提交前做代码检查 pnpm dlx husky-in…

C语言项⽬实践-贪吃蛇

目录 1.项目要点 2.窗口设置 2.1mode命令 2.2title命令 2.3system函数 2.Win32 API 2.1 COORD 2.2 GetStdHandle 2.3 CONSOLE_CURSOR_INFO 2.4 GetConsoleCursorInfo 2.5 SetConsoleCursorInfo 2.5 SetConsoleCursorPosition 2.7 GetAsyncKeyState 3.贪吃蛇游戏设…

nfs服务器--RHCE

一,简介 NFS(Network File System,网络文件系统)是FreeBSD支持的文件系统中的一种,它允许网络中的计 算机(不同的计算机、不同的操作系统)之间通过TCP/IP网络共享资源,主要在unix系…

自动化运维(k8s):一键获取指定命名空间镜像包脚本

前言:脚本写成并非一蹴而就,需要不断的调式和修改,这里也是改到了7版本才在 生产环境 中验证成功。 该命令 和 脚本适用于以下场景:在某些项目中,由于特定的安全或政策要求,不允许连接到你的镜像仓库。然而…

HuggingFace:基于YOLOv8的人脸检测模型

个人操作经验总结 1、YOLO的环境配置 github 不论base环境版本如何,建议在conda的虚拟环境中安装 1.1、创建虚拟环境 conda create -n yolov8-face python3.9conda create :创建conda虚拟环境, -n :给虚拟环境命名的…

Unet++改进28:添加PPA(2024最新改进方法)|多分支特征提取策略,捕获不同尺度和层次的特征信息。

本文内容:添加PPA 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 红外小目标检测是一项重要的计算机视觉任务,涉及对红外图像中通常只有几个像素的微小目标进行识别和定位。然而,由于红外图像中物体的体积小,背景一般比较复杂,这给红外图像的识别带来…

CTF攻防世界小白刷题自学笔记13

1.fileinclude,难度:1,方向:Web 题目来源:宜兴网信办 题目描述:无 给一下题目链接:攻防世界Web方向新手模式第16题。 打开一看给了很多提示,什么language在index.php的第九行,flag在flag.php中,但事情显…

同三维T610UDP-4K60 4K60 DP或HDMI或手机信号采集卡

1路DP/HDMI/TYPE-C(手机/平板等)视频信号输入1路MIC1路LINE OUT,带1路HDMI环出,USB免驱,分辨率4K60,可采集3路信号中其中1路,按钮切换,可采集带TYPE-C接口的各品牌手机/平板/笔记本电脑等 同三维…

小程序如何完成订阅

小程序如何完成订阅 参考相关文档实践问题处理授权弹窗不再触发引导用户重新授权 参考相关文档 微信小程序实现订阅消息推送的实现步骤 发送订阅消息 小程序订阅消息(用户通过弹窗订阅)开发指南 实践 我们需要先选这一个模板,具体流程参考…

解决Xeyes: Error can‘t open display,远程X无法连通问题。

一、问题分析 提前申明: 本次实验使用REHL 8 进行操作! 客户机 A 为X-Client ,即远程X的客户端。 服务机 B 为X-Server,即远程X的服务端。 问题的所有操作均在已经配置好Xorg的前提下进行的,不知道不配置会有什么影响&…

JS学习日记(jQuery库)

前言 今天先更新jQuery库的介绍,它是一个用来帮助快速开发的工具 介绍 jQuery是一个快速,小型且功能丰富的JavaScript库,jQuery设计宗旨是“write less,do more”,即倡导写更少的代码,做更多的事&#xf…

华为HCIP——MSTP/RSTP与STP的兼容性

一、MSTP/RSTP与STP的兼容性的原理: 1.BPDU版本号识别:运行MSTP/RSTP协议的交换机会根据收到的BPDU(Bridge Protocol Data Unit,桥协议数据单元)版本号信息自动判断与之相连的交换机的运行模式。如果收到的是STP BPDU…

基于YOLOv8深度学习的智慧课堂学生专注度检测系统(PyQt5界面+数据集+训练代码)

本研究提出了一种基于YOLOv8深度学习的智慧课堂学生专注度检测系统,旨在实现对课堂中学生专注度的实时分析与评估。随着智慧教育的快速发展,学生的课堂表现和专注度成为评估学习效果的重要因素之一。然而,传统的专注度评估方法往往依赖于主观…

【汇编】c++游戏开发

由一起学编程创作的‘C/C项目实战:2D射击游戏开发(简易版), 440 行源码分享来啦~’: C/C项目实战:2D射击游戏开发(简易版), 440 行源码分享来啦~_射击c-CSDN博客文章浏览…

QT_CONFIG宏使用

时常在Qt代码中看到QT_CONFIG宏,之前以为和#define、DEFINES 差不多,看了定义才发现不是那么回事,定义如下: 看注释就知道了QT_CONFIG宏,其实是:实现了一个在编译时期安全检查,检查指定的Qt特性…