Redis实现分布式锁详细解读

news2024/11/24 10:36:05

文章目录

    • 什么是分布式锁?
    • 如何用Redis实现分布式锁?
    • 分布式锁的改进
    • 锁过期处理
    • 集群环境下Redis宕机问题
    • RedLock的引入
    • RedLock的实现步骤
    • RedLock带来的弊端

什么是分布式锁?

我们在学多线程的时候遇到过ReetrantLock,这种锁主要应用于多线程竞争资源。如果是多进程竞争资源的话就需要引入分布式锁的概念了。比如在微服务架构中,多个用户进程修改同一条数据且只能有一个用户修改成功,就需要用到分布式锁,今天我们就来讲讲如何用redis来实现分布式锁。

如何用Redis实现分布式锁?

使用redis中的String类型。
redis中有set NX(set if not exists)命令可以实现当key不存在时才插入,如果key已经存在,则不做任何操作。

  • 如果key不存在,那么插入成功,表示获取锁成功。
  • 如果key存在,那么插入失败,表示获取锁失败。

获取锁:
假设客户端A已经使用setnx命令实现了获取锁的操作(获取锁成功会返回1)

setnx try_lock 1

那么此时客户端B再次使用setnx命令时会失败(获取锁失败会返回0)
释放锁:
只有当客户端A使用del命令释放锁,客户端B才能获取锁成功

del try_lock 

以上只是简单的获取锁和释放锁的操作,还存在很多弊端:

  • 设想一种情况,如果客户端A在获取锁之后宕机了,那么try_lock也就永远不会被删除,所以就会一直存在redis中,也就是说其他客户端永远拿不到锁,无法执行业务,这个bug太大了!
  • 还有一个缺点就是,任何客户端都可以释放这把锁,所以我们需要为这把锁设置一个唯一标识,只有设置这把锁的用户才有权利释放这把锁。
setnx key unique_value
//释放锁 比较unique_value是否相等,避免误释放
if redis.get("key") == unique_value then
    return redis.del("key")

可以看到释放锁的步骤具体由GET和DEL操作实现,因为这是两个操作,所以就涉及到原子性问题了,具体问题如下:

  • 客户端A执行get命令判断锁是自己的
  • 客户端B重新加锁(假设客户端A加的锁刚好过期的时候)
  • 客户端A执行del命令释放锁(那么客户端A释放的就是客户端B加的锁)

为了解决上述问题,可以使用Lua脚本(因为Redis处理每个请求是单线程执行的,在执行一个Lua脚本时其它请求必须等待,直到这个Lua脚本处理完成):
KEYS[1]即为try_lockARVG[1]是客户端的唯一表示

if redis.call("get",KEYS[1]) == ARVG[1] then
   return redis.call("del",KEYS[1])
else
   return 0
end

分布式锁的改进

基于以上try_lock永远无法被删除的情况,可以引入过期时间。这样一来,如果某个客户端在获取锁之后宕机了,因为有过期时间的存在,所以key在一定时间之后也会失效,其他客户端就可以继续获取锁进行操作了。

比如:
设置一个serverLock,并且10s之后过期

set serverLock 1 nx ex 10

就可以解决上述问题了,但是又会发生新的问题:

如果一个业务执行的时间过长,导致在获取锁之后的10s内无法完成,所以redis就会在业务执行完之前释放锁,释放锁之后,后进来的第二个进程就可以重新加锁,并且也可以执行业务操作,假设第一个进程在第15s执行完业务,由于在第10s的时候锁已经过期(第二个进程在第11s进行可以加锁),那么第一个进程执行完业务之后所释放的就是第二个进程加的锁,并且在第11s到第15s之间第一个进程和第二个进程在同时执行业务,就会导致数据冲突。

锁过期处理

基于以上锁过期问题,我们可能会想到延长锁的过期时间。比如本来过期时间是10s,我们改为100s。但是这样的话,回到最初的问题,如果客户端在获取锁之后宕机,100s之后这个锁才会过期,也就意味着整整100s内其余客户端是无法获取锁的!对于高并发的应用来说,100s的时间是相当长的!

既然延长锁的过期时间行不通,那怎么办?

我们可以在执行业务的过程中延长锁的过期时间,其实本质上还是延长过期时间,只不过这种做法效率比较高。

如果在业务执行过程中,锁快要过期了,我们可以适当延长锁的过期时间(延长的时间短一些,延长的次数多一些)这样就不会发生在长时间内其余客户端无法获取锁的情况了。
具体实现就是为锁设置一个守护线程,定时去检测锁的过期时间,如果锁快过期了,就为锁延长过期时间。

集群环境下Redis宕机问题

我们都知道为了保证高可用,redis一般都是基于集群来分布的,并且redis主从节点之间的数据传输是异步的。假设redis主节点获取锁之后宕机,数据还没有来得及同步到从节点,由于数据不一致问题,执行切主操作之后新的主节点依然可以获取锁,所以会产生数据冲突。

RedLock的引入

基于集群环境下分布式锁产生的问题,可以引入RedLock(红锁)。不过要想使用RedLock需要一个特定的环境,即至少有五个节点,这五个节点都是主节点且孤立存在。

RedLock的基本思想就是对所有的主节点进行加锁操作,如果能对半数以上的节点加锁,那么就认为客户端加锁成功,否则的话加锁失败。这样一来,如果集群环境下某个主节点获取锁之后宕机了,那么此时其余主节点也依然拥有锁,所以客户端依然可以进行后续的操作,锁住的数据也不会丢失。

RedLock的实现步骤

  • 客户端先获取当前时间T1
  • 客户端向N个主节点开始加锁,加锁时需要使用set nx命令并且为锁设置过期时间并且需要带上客户端的唯一标识。还需要另外给加锁操作设置一个超时时间,这个超时时间要远小于锁的过期时间。
  • 客户端一旦对半数以上的节点加锁成功,那么客户端会再次获取一个当前时间T2,然后计算T2-T1的值,如果这个值小于锁的过期时间,那么就认为加锁成功。
  • 如果加锁成功,可以继续后面的业务操作;如果加锁失败,需要释放掉所有的锁

可见,RedLock加锁需要满足两个条件:

  • 能对半数以上的节点加锁成功
  • T2-T1的值小于锁的过期时间

RedLock带来的弊端

  • 需要额外部署redis主节点,花费很高,并且运维的成本也比较高。
  • 通过RedLock的加锁操作可以看出RedLock锁比较重,操作起来很麻烦。
  • 主从切换的情况很少见,所以为了极少情况的发生选用RedLock性价比不高。

在这里插入图片描述

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

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

相关文章

node install编译失败原因

关键报错信息 npm ERR! gyp verb check python checking for Python executable "python2.7" in the PATH npm ERR! gyp verb which failed Error: not found: python2.7 或者 npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! Whi…

车载以太网时间同步之EthTsync

车载以太网时间同步之EthTsync 前言 首先,请问大家几个小小问题,你清楚: 你知道EthTsync模块的主要作用是什么吗?EthTsync模块与其他AUTOSAR基础软件模块交互关系;Eth Tsync模块使用的时间同步协议是什么&#xff1f…

Java—JDK8新特性—函数式接口

目录 函数式接口 3.1 什么是函数式接口 3.2 functionalinterface注解 源码分析 3.3 Lambda表达式和函数式接口关系 3.4 使用函数式接口 函数式接口 3.1 什么是函数式接口 如果一个接口中只包含一个抽象方法,这个接口称为函数式接口 如果一个接口包含&#xff0…

mac php8 安装xdebug模块失败

安装 xdebug 模块,官网有详细介绍Xdebug: Documentation Installation 本机是mac php使用brew安装,想着可以直接使用以下方式安装,还是美滋滋的 但是安装途中发生了错误 PHP Warning: mkdir(): File exists in /usr/local/Cellar/php/8.0.10/share/php/pear/System.php on…

解决报错ERROR: No matching distribution found for torchvision==0.11.2+cu111

目录 一、猜测 二、验证 三、解决方案 四、检验 该报错是在按官网方法用指令: pip install torch1.9.1cu111 torchvision0.10.1cu111 torchaudio0.9.1 -f https://download.pytorch.org/whl/torch_stable.html 安装pytorch时出现的,以下是分析&#…

粗糙集属性约简方法与Python实现【1】

1. 方法概述 1.1 定义 粗糙集是波兰理工大学Z.pawlak教授提出用来研究不完整数据,不精确知识的表达、学习,归纳等的一套理论。它是一种新的处理模糊和不确定性问题的数学工具,已被广泛应用于知识发现、机器学习、决策支持、模式识别、专家系统及归纳推理等领域。 粗糙集理…

开源相亲小程序

此项目目前已完成前台开发。源码结构清晰,完美实现模块化组件化思想,易维护。 曾经,作者也为寻求自己的另一半苦恼,因为平时工作繁忙,交际圈窄小,而父母又各种催婚,无奈上了“XX网”去碰碰运气。…

webpack5搭建react框架-antd组件库使用

antd组件库使用 一、前言 前面已经完成了webpack5 react框架的配置搭建,我们在进行项目开发的时候大多还会使用第三方的组件库,而antd组件库在react项目中使用是非常非常多的,所以就将react框架使用最多的antd组件库引入并使用。 二、ant…

京东给了兄弟姐妹们稳稳的幸福

“今天我看了宿舍楼,我真的是气得想打人;我原来一直说的是高级单身公寓!可实际情况呢?我说了多少遍了,要让员工、让兄弟们活的有尊严。而我们宿迁分公司的管理层是怎么做的呢,说难听的就是没有把员工当人去…

低代码平台的多租户SAAS系统实战解决方案—JeecgBoot

JeecgBoot免费低代码平台,提供一键切换多租户模式机制!快速实现全系统的saas租户方案,通过租户ID进行数据隔离。 租户设计思路 1、开启全系统租户隔离 开启方法 将 org.jeecg.config.mybatis.MybatisPlusSaasConfig#OPEN_SYSTEM_TENANT_CO…

RabbitMQ --- 消息可靠性

消息队列在使用过程中,面临着很多实际问题需要思考: 一、消息可靠性 消息从发送,到消费者接收,会经理多个过程: 其中的每一步都可能导致消息丢失,常见的丢失原因包括: 发送时丢失: …

(java)继承和多态 (详解)

目录 1 继承 1.1为什么需要继承 1.2 继承概念 1.3 继承的语法 1.4 父类成员访问 1.4.1 子类中访问父类的成员变量 1.4.2 子类中访问父类的成员方法 1.5 super关键字 1.6 子类构造方法 1.7 super和this 1.7.1 this 1.7.2 super和this 1.8 再谈初始化 1.9 继承方…

软考信管高级——人力资源管理

人力资源管理内容 人力资源管理计划 内容: 角色与职责:定义项目所需的岗位、技能和能力项目组织图,说明项目所需的人员数量人员配备管理计划,说明需要每个团队的时间段以及有助于项目团队参与的其他重要信息 成功的项目团队的特…

Linux安装java jdk

1、检查系统中jdk 版本:java -version 2、检测 jdk 安装包:rpm -qa | grep java 3、卸载 openjdk rpm -e --nodeps tzdata-java-2017b-1.el7.noarch rpm -e --nodeps java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64 rpm -e --nodeps java-1.8.0-open…

深度学习细节总结

计算机视觉 目标检测,语义分割,目标分类 自然语言处理NLP 数据结构 数据结构 访问元素 线性回归 可以看成是一个单层的神经网络,有显式的解 优化算法 梯度下降,超参数:学习率、批量大小 分类回归 单层感知机…

RuntimeError:cuDNN error:CUDNN_STATUS_EXECUTION_FAILED

背景 最近在服务器上跑Deeplabv3进行语义分割时,需要使用GPU版的pytorch。 我在Anaconda下配置了适配服务器CUDA的pytorch,但是报错如下,(下图无限接近于我的错误,但是我忘记截图我的报错了,所以用了下面这…

魔百盒CM211-1S_ZG_增强版2+16_当贝纯净版桌面-卡刷固件包

魔百盒CM211-1S_ZG_增强版216_当贝纯净版桌面-卡刷固件包-内有教程-华为鸿蒙动画 特点: 1、适用于对应型号的电视盒子刷机; 2、开放原厂固件屏蔽的市场安装和u盘安装apk; 3、修改dns,三网通用; 4、大量精简内置的…

图灵java学习

反汇编 最后一行 效果是 程序计数器,保存下一个指令的地址 iadd. int加法 动态链接 Java动态链接(Dynamic Linking)是Java中的一种运行时特性,它允许在应用程序运行时动态地链接和加载库和组件。在编译时,Java程序不需…

逆向效率提升工具与方法汇总(持续更新...)

欢迎大家提供高效方法与工具 工具油猴插件SwitchyOmegaReresFiddler插件编程猫 奇淫技巧seleniumOptions常用参数防检测将浏览器navigator.webdriver重置为Falsestealth.min.js解决常见的指纹检测浏览器worker完美解决检测 小试牛刀chrome开发者工具设置中文调试代码如何友好格…

【MySQL】(创建,查看,使用,删除)数据库

目录 一.Cmd命令执行操作 1.使用cmd命令进入数据库(mysql -uroot -p) 2.查看数据库 3.创建数据库 4.使用数据库 5.删除数据库 二.数据库软件执行操作 1.查看数据库 2.创建数据库 3.数据库 4.删除数据库 一.Cmd命令执行操作 1.使用cmd命令进入数据库&#…