【Redis知识点总结】(五)——Redis实现分布式锁

Redis知识点总结(五)——Redis实现分布式锁

  • setnx
  • setnx + expire
  • setnx + expire + lua脚本
  • set nx ex
  • set nx ex + 随机值
  • set nx ex + 随机值 + lua脚本
  • set ex nx + 随机值 + lua脚本 + 锁续期
  • Redisson
  • RedLock

在Redis的众多应用场景中,分布式锁是Redis比较重要的一个应用场景,今天我们就来了解一下如何用Redis实现一个分布式锁。

setnx

Redis提供了一个setnx命令,它的作用是在给缓存设置值时,判断key是否存在,如果key已经存在,则不执行操作,只有当缓存中不存在指定key时,才设置该缓存。

使用setnx命令,就可以实现一个简单的分布式锁。我们指定一个特定的值作为setnx命令的key,然后当一个线程要获取分布式锁时,就要通过setnx命令在redis中设置该key,如果设置成功,代表获取分布式锁成功,如果设置失败,表示获取分布式锁失败,那么当前线程就要通过自旋加sleep的机制等待别的线程释放锁。

一个线程通过setnx命令获取到分布式锁后,通过del命令释放锁。释放锁之后,其他线程就可以再次尝试获取锁。

在这里插入图片描述

但是这种方案有一个严重的问题,就是当一个线程获取到锁后,在处理业务逻辑时发生了异常,或者直接宕机了,没能执行del命令释放锁,那么其他线程就会一直获取不到锁。

setnx + expire

单靠setnx命令实现的分布式锁,存在锁得不到释放的风险。因此,我们可以引入expire命令,给key设置一个过期时间。当一个线程执行setnx命令成功后,就通过expire命令给该key设置一个过期时间。假如该线程执行业务逻辑出错,没能执行del命令,那么等该key的过期时间到后,该key也会被失效清理,锁最终还是能得到释放的。

在这里插入图片描述

这样问题就解决了吗?

显然是没有的,因为setnx和expire是两条命令,是非原子性的,如果setnx执行成功,expire命令执行失败,那么锁还是得不到释放。

setnx + expire + lua脚本

setnx命令与expire命令的非原子性问题,可以通过lua脚本去解决,把setnx和expire两条命令包在一个lua脚本里面,就可以保证这两条命令同时成功或者同时失败,这就就具备了原子性。

在这里插入图片描述

除了使用lua脚本,Redis还可以通过一条命令实现setnx加expire两条命令的功能。

set nx ex

我们可以通过以下命令实现setnx命令加expire命令的功能,并且可以保证原子性:

set key value nx ex {过期时间}

在这里插入图片描述

这样,分布式锁得不到释放的问题就彻底解决了。

但是,这样就没问题了吗?显然不是的,还会出现以下这种情况:

在这里插入图片描述

线程1获取分布式锁成功,但是业务处理时间过长,锁早已过期。而线程2随后获取分布式锁成功,进行业务处理。然后这时候线程1处理完了,于是执行del命令释放锁,而此时它释放的是线程2加的锁,并且线程2还没有处理完。线程2的锁被线程1释放后,如果线程3到来,也获取了分布式锁,那么等线程2处理完毕,又会释放掉线程3获取的锁,以此类推,这个分布式锁就失效了。

set nx ex + 随机值

锁错误释放的问题,可以通过给value指定一个随机值来解决,实现方案是这样:

在这里插入图片描述

执行set命令时生成一个随机值作为value值,并且当前线程要保存该随机值。等到当前线程处理完业务逻辑要准备释放锁时,先拿着自己保存的随机值跟redis中的value比对一下,如果相等,才执行del命令释放锁,否则就不能执行del命令。

这样看似可以解决锁误删的问题,一般情况下也确实如此,但是在高并发场景下,有可能会出现以下这种情况:

在这里插入图片描述

线程1执行完业务逻辑后,判断自己的value随机值与redis中的value相等,正准备释放锁,此时正好锁过期了,然后线程2又刚好获取到了锁,然后线程1才执行del命令,那么线程2的锁又被误释放了。

这是低概率事件,非高并发场景其实不用考虑这个问题,但是在高并发场景,还是有可能出现的。问题的原因是if判断与del命令是两个操作,非原子性。

set nx ex + 随机值 + lua脚本

if判断与del命令的非原子性问题,可以通过lua脚本解决,把if判断与del命令用lua脚本包起来,就可以彻底解决锁误释放的问题。

在这里插入图片描述

现在获取锁与释放锁的操作都是原子性的,我们的分布式锁也逐步变得完善,但是还有一个问题,那就是锁过期,也就是业务处理还未结束,锁就过期的这种情况。

我们可以给锁设置一个较长的过期时间,但是我们无法百分之一百保证所有的业务处理都在锁过期前得到释放,如果在某种特殊情况下处理时间比平常的要长,锁还是过期了,那么还是有问题的。

set ex nx + 随机值 + lua脚本 + 锁续期

锁过期的解决办法,就是开一个“看门狗”线程,进行锁续期,这个线程会定时地不断的检测主线程释放处理完毕并且释放了锁,如果主线程还没有处理完毕,那么这个“看门狗”线程就会执行expire命令进行锁续期。

在这里插入图片描述

此时,我们的分布式锁就完美了。但是,这样太复杂了吧?我们为了实现一个分布式锁,居然要处理这么多问题,使得原本简单的代码变得非常复杂,那有没有一个开源框架,可以帮我们实现这一切,我们只需要简单的调用一下就完事了呢?

当然是有的,那就是使用Redisson的分布式锁。

Redisson

Redisson是一个用Java语言实现的用于操作Redis的客户端工具包,比起原生的Jedis工具包,Redisson是更好用,功能更强大的。

Redisson就自带了分布式锁的实现,把我们上面说到的获取锁的原子性、释放锁的原子性、利用看门狗线程进行锁续期等一系列的操作都包装起来,对外暴露了简单的获取锁和释放锁的方法,我们无需手动编码实现这复杂的获取锁与释放锁的逻辑,只要使用Redisson提供的分布式锁的方法,就可以实现分布式锁的功能。

在这里插入图片描述

使用Redisson,我们就可以轻松简单的实现分布式锁的功能,但是如果Redis是单节点的话,Redis宕机了,那么所有线程都无法获取到锁了。

在这里插入图片描述

解决Redis单节点的问题,自然是上多个Redis节点。但是上了多个Redis节点之后,分布式锁又怎么实现呢?

RedLock

Redis的作者提出了一个多redis节点的分布式锁实现方案,那就是RedLock。

首先,我们要启5个redis节点,但是这5个节点是独立的节点,互相之间没有主从关系,也没有组成集群。

当一个线程加锁时,需要按顺序的访问这五个节点,还是利用set nx ex或set nx px命令进行加锁。

当一个线程在至少3个以上的redis节点成功执行了set命令,那么就表示获取锁成功,此时该线程要计算锁的有效期,需要用锁的有效期减去加锁耗费的时间,如果还有剩余时间,表示获取锁成功,如果没有剩余时间了,那么表示获取锁失败。

如果一个线程获取锁失败,要按相反的顺序向所有redis节点执行del命令释放锁。

在这里插入图片描述

这个RedLock的功能,同样可以通过Redisson实现,只需要调用Redisson提供的简单的API方法即可,无需我们编写复杂的RedLock代码。

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

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

相关文章

解决分布式事务,Seata真香!

年IT寒冬,大厂都裁员或者准备裁员,作为开猿节流主要目标之一,我们更应该时刻保持竞争力。为了抱团取暖,林老师开通了《知识星球》,并邀请我阿里、快手、腾讯等的朋友加入,分享八股文、项目经验、管理经验等…

纯 CSS 实现文字换行环绕效果

实现效果 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title><…

Windows10中配置并使用nvidia-smi

1. 问题 当在window10系统中使用nvidia-smi命令时&#xff1a; 会得到提示&#xff1a;nvidia-smi不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 注&#xff1a;其实安装NVIDIA控制面板时&#xff0c;软件已内置安装了nvidia-smi.exe&#xff0c;我们只需…

如何彻底删除Windows10系统D盘文件夹中的DeliveryOptimization

DeliveryOptimization是传递优化创建的文件夹。Windows 10的Delivery Optimization&#xff08;传递优化&#xff09;功能是用于加快下载Windows更新及其他Microsoft Store应用程序的速度的一种技术。Delivery Optimization使用了一个名为“DeliveryOptimization”&#xff08;…

zookeeper快速入门五:用zookeeper实现服务注册与发现中心

系列&#xff1a; zookeeper快速入门一&#xff1a;zookeeper安装与启动-CSDN博客 zookeeper快速入门二&#xff1a;zookeeper基本概念-CSDN博客 zookeeper快速入门三&#xff1a;zookeeper的基本操作 zookeeper快速入门四&#xff1a;在java客户端中操作zookeeper-CSDN博客…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:TabContent)

仅在Tabs中使用&#xff0c;对应一个切换页签的内容视图。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 支持单个子组件。 说明&#xff1a; 可内置系统组件和自定义组件&#xff0c;支…

运用html相关知识编写导航栏和二级菜单

相关代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><s…

Java代码审计安全篇-CSRF漏洞

前言&#xff1a; 堕落了三个月&#xff0c;现在因为被找实习而困扰&#xff0c;着实自己能力不足&#xff0c;从今天开始 每天沉淀一点点 &#xff0c;准备秋招 加油 注意&#xff1a; 本文章参考qax的网络安全java代码审计和部分师傅审计思路以及webgoat靶场&#xff0c;记录…

[嵌入式系统-40]:龙芯1B 开发学习套件 -10-PMON启动过程start.S详解

目录 一、龙芯向量表与启动程序的入口&#xff08;复位向量&#xff09; 1.1 复位向量&#xff1a; 1.2 代码执行流程 1.3 计算机的南桥 VS 北桥 二、PMON代码执行流程 三、Start.S详解 3.1 CPU初始化时所需要的宏定义 &#xff08;1&#xff09;与CPU相关的一些宏定义…

关于Ubuntu虚拟机识别不了USB设备的解决方案

唉昨天从网上找了一天的解决方案都没法让我的Ubuntu虚拟机识别USB设备&#xff0c;CSDN上有些方法是让从控制面板中进行修复&#xff0c;很多人都是一样的做法链接&#xff0c;那我觉得应该是可以解决的啊&#xff01; 结果我去控制面板执行修复的时候&#xff0c;显示报错“没…

基于Matlab的图像去雾系统设计,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

第二百零八回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"给geolocator插件提交问题的结果"相关的内容&#xff0c;本章回中将介绍自定义标题栏.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我…

在Windows系统上搭建MongoDB-这篇文章刚刚好

在Windows系统上搭建MongoDB集群 文章目录 1.下载MongoDB2.集群描述3.构建集群文件目录4.新建配置文件5.启动MongoDB服务6.配置集群7.集群测试8.设置密码和开启认证一、安装MongoDB 1.下载MongoDB 去MongoDB官网下载解压版免安装的压缩包。 https://www.mongodb.com/try/do…

C语言 数据在内存中的存储

目录 前言 一、整数在内存中的存储 二、大小端字节序和字节序判断 2.1.练习一 2.2 练习二 2.3 练习三 2.4 练习四 2.5 练习五 2.6 练习六 三、浮点数在内存中的存储 3.1 浮点数存的过程 3.2 浮点数取的过程 总结 前言 数据在内存中根据数据类型有不同的存储方式&#xff0c;今…

使用ChatGPT高效完成简历制作[中篇]-有爱AI实战教程(五)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 导读&#xff1a;在使用 ChatGPT 时&#xff0c;当你给的指令越精确&#xff0c;它的回答会越到位&#xff0c;举例来说&#xff0c;假如你要请它帮忙写文案&#xff0c;如果没…

服务器开机不输入密码自动进系统, 与设置开机启动项

打开运行[win R ] 输入&#xff1a; control Userpasswords2设置开机启动项 运行 输入 shell:startup在这里插入图片描述

蓝桥杯2022年第十三届省赛真题-数的拆分

solution1&#xff08;通过10%&#xff09; #include<stdio.h> #include<math.h> typedef long long LL; int isPrime(LL n){LL sqr (int)sqrt(1.0 * n);for(int i 2; i < sqr; i){if(n % i 0) return 0;}return 1; } int main(){int t;LL a;scanf("%d…

如何用saga实现分布式事务?

SAGA事务介绍 SAGA事务模式的历史十分悠久&#xff0c;比分布式事务的概念提出还要更早。SAGA的意思是“长篇故事、长篇记叙、一长串事件”&#xff0c;它起源于1987年普林斯顿大学的赫克托 加西亚 莫利纳&#xff08;Hector Garcia Molina&#xff09;和肯尼斯 麦克米伦&a…

phpstudy搭建简单渗透测试环境upload-labs、DVWA、sqli-labs靶场

好久没有做渗透相关的试验了&#xff0c;今天打开phpstudy发现很多问题&#xff0c;好多环境都用不了&#xff0c;那就卸载重装吧&#xff0c;顺便记录一下。 小皮下载地址&#xff1a; https://www.xp.cn/download.html 下载安装完成 一、下载搭建upload-labs环境 github…

训练YOLOv8m时AMP显示v8n

在训练Yolov8模型时&#xff0c;使用AMP&#xff08;Automatic Mixed Precision&#xff09;可以加速训练过程并减少显存的使用。AMP是一种混合精度训练技术&#xff0c;它通过将模型参数的计算转换为低精度&#xff08;如半精度&#xff09;来提高训练速度&#xff0c;同时保持…