如何通俗易懂的理解Redis分布式锁

一、前言
首先我们先考虑以下这个问题:

在多线程并发的情况下,我们如何保证一个代码块在同一时间只能由一个线程访问呢?

答案:通常来说,我们可以用锁来保证。比如java的synchronized用法以及ReentrantLock等等。这样就可以保证同一个JVM进程内的多个线程同步执行。

那么如果在分布式的集群环境中,如何保证不同结点的线程同步执行呢?

对于分布式场景,我们可以尝试用分布式锁。

二、分布式锁的实现有哪些呢?
a.Memcached分布式锁

利用Memcached的add命令。此命令是原子性操作,只有在key不存在的情况下,才能add成功,也就意味着线程得到了锁。

b.Redis分布式锁

和Memcached的方式类似,利用Redis的setnx命令。此命令同样是原子性操作,只有在key不存在的情况下,才能set成功。(setnx命令并不完善,后续会介绍替代方案)

c.Zookeeper分布式锁

利用Zookeeper的顺序临时节点,来实现分布式锁和等待队列。Zookeeper设计的初衷,就是为了实现分布式锁服务的。

三、如何用Redis来实现分布式锁呢?
3.1 分布式锁的三个核心要素
1.加锁
使用setnx来加锁。key是锁的唯一标识,按业务来决定命名,value这里设置为test。

setx key test

当一个线程执行setnx返回1,说明key原本不存在,该线程成功得到了锁;当一个线程执行setnx返回0,说明key已经存在,该线程抢锁失败;

2.解锁
有加锁就得有解锁。当得到的锁的线程执行完任务,需要释放锁,以便其他线程可以进入。释放锁的最简单方式就是执行del指令。

del key

释放锁之后,其他线程就可以继续执行setnx命令来获得锁。

3.锁超时
锁超时知道的是:如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资源将会永远被锁住,别的线程北向进来。

所以,setnx的key必须设置一个超时时间,以保证即使没有被显式释放,这把锁也要在一段时间后自动释放。setnx不支持超时参数,所以需要额外指令,

expire key 30

3.2 上述分布式锁存在的问题
通过上述setnx 、del和expire实现的分布式锁还是存在着一些问题。下面将具体举例说明该问题:

1.setnx和expire的非原子性问题
假设一个场景中,某一个线程刚执行setnx,成功得到了锁。此时setnx刚执行成功,还未来得及执行expire命令,节点就挂掉了。此时这把锁就没有设置过期时间,别的线程就再也无法获得该锁。

解决措施:

由于setnx指令本身是不支持传入超时时间的,而在Redis2.6.12版本上为set指令增加了可选参数, 用法如下:

SET key value [EX seconds][PX milliseconds] [NX|XX]

EX second: 设置键的过期时间为second秒;
PX millisecond:设置键的过期时间为millisecond毫秒;
NX:只在键不存在时,才对键进行设置操作;
XX:只在键已经存在时,才对键进行设置操作;
SET操作完成时,返回OK,否则返回nil。
2.del导致误删
假设在这样一个场景当中,假如某线程成功获得了锁,并且设置的超时时间是30秒。

但是如果由于某些原因导致线程A执行的速度很慢,过了30s都还没执行完成,这时候锁过期自动释放,线程B得到了锁。

随后,线程A执行完了任务,线程A接着执行del指令来释放锁,但这时候线程B还没执行,线程A实际上删除的是线程B加的锁,

解决办法:

在del释放锁之前加一个判断,验证当前的锁是不是自己加的锁。

具体在加锁的时候把当前线程的id当做value,在删除之前验证key对应的value是不是自己线程的id;

3.出现并发的可能性
第三个问题其实还是刚才第二点所描述的场景。虽然避免了线程A误删掉key的情况,但是同一时间有A和B两个线程在访问代码块,还是不完美的。

解决办法:

可以让获得锁的线程开启一个守护线程,用来给快要过期的锁”续航“。

当过去了29秒,线程A还没执行完,这时候守护线程会执行expire指令,为这把锁“续命”20秒。守护线程从第29秒开始执行,每20秒执行一次。当线程A执行完任务,会显式关掉守护线程。

另一种情况,如果节点1 忽然断电,由于线程A和守护线程在同一个进程,守护线程也会停下。这把锁到了超时的时候,没人给它续命,也就自动释放了。
 

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

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

相关文章

Python:解决with打开文件错误UnicodeDecodeError

简介:在使用with打开部分编码不是utf-8和gbk时,可能出现报错UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0xff in position 0: illegal multibyte sequence. UnicodeDecodeError 是一个很常见的错误,它通常在你试图解码一个特定编…

三阶魔方七步解法-最后还原顶层顶角(不是顶棱)

主要区别,最后一步是 顶层十字棱角已经还原,四个顶角的位置正确,但四个顶角的颜色没有对应。 因为现在基本都是6步还原法(找什么小鱼,眼睛),是先还原顶层使颜色一致,最后还原顶棱。但…

云原生之深入解析使用Telepresence轻松在本地调试和开发Kubernetes应用程序

一、 准备 telepresence 下载:https://www.telepresence.io/docs/latest/install/kubectl 下载:https://kubernetes.io/docs/tasks/tools/ 二、版本检测 $telepresence version Client: v2.5.3 (api v3) Root Daemon: not running User Daemon: not r…

leetcode面试经典二分系列刷题心得

闲来无事巩固算法基础,发现自己的二分几乎从来没系统刷过题,基础很是薄弱。 二分法不愧称为新人杀手,刷起来很是吃力,感觉明明学了几套二分模板,但是却不知道如何去运用,很多读者在初次尝试刷二分题时候&a…

陆[6],函数hommat2didentity/HomMat2dRotate/HomMat2dScale/HomMat2dTranslate/

函数hommat2didentity 函数功能 生成一个初始矩阵[1,0,0,0,1,0] C形式 LIntExport void HomMat2dIdentity( HTuple* HomMat2DIdentity);//参数1:输出初始矩阵 C#形式 public static void HomMat2dIdentity( out HTuple homMat2DIdentity); 函数HomMat2dRotate 函数功能…

计算机网络 internet应用 (水

ARPA net ---Internet 前身 发展史: ARPA net 第一个主干网..美国军方NSFnet 美国国家科学基金会NSFANSnet 美国全国 (internet 叫法开始出现) 第二代互联网(现在() IP地址 IP地址 最高管理机构 - InterNIC IPV4 32位 IPV6 128位 域名 起名 解析 domain name sys…

24款奔驰C260L升级C63包围 典型的花小钱办大事

今天店里来了一台24款奔驰C260L 一提车就过来升级 我们公司还有包上牌服务 车主说 升级完包围 帮忙安排一下 原车的包围 没有那么霸气 特别是后杠 光溜溜的 升级后 四出尾喉 尾翼 直接牌面就起来了 星骏汇小许Xjh15863

Android12-RK3588_s-开机动画

目录 一、实现自定义开机动画 步骤一:准备 bootanimation.zip 步骤二:将 bootanimation.zip 放到 /system/media/bootanimation.zip下 步骤三:重启即可 二、注意事项 2.1 bootanimation.zip 压缩 2.2 bootanimation.zip 存放 2.3 boo…

打印机设置发票收据打印

由于各种打印机型号不一样,设置方式打印效果出入也很大,存在打印不全问题,发票右侧小数点后面的数字打印不出来、位置靠上下左右登问题,比较通用的设置方式如下: 首先找到控制面板,找到设备和打印机 进入到…

Git使用无法拉取

错误提示: error setting certificate verify locations: CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt CApath: none 问题原因: 这个问题是因为git配置里crt证书的路径不正确导致的 解决办法: 这个路径配置是在C:\Pro…

【C语言】printf()函数详解,手把手教你,保姆级!!!

目录 基本用法 printf()函数--占位符 占位符大全 printf()函数--限定宽度 printf()函数--正负--限定小数 printf()函数--输出部分字符串 总结 【C语言】printf()函数详解,手把手教你,保姆级!!! 基本用法 printf()…

【HDFS】FsDatasetSpi#adjustCrcChannelPosition

FsDatasetSpi接口里定义adjustCrcChannelPosition方法。 应用场景在:append,block recovery等场景。 方法的作用是设置checksum 流(datanode上meta文件)的文件指针,来让最后一个checksum被覆写。 /*** Sets the file pointer of the checksum stream so that the last ch…

openoffice安装

安装openoffice 下载安装包 建议去官网下载,这里给出官网地址:https://www.openoffice.org/download/ 这里以linux为例,所以我下载的是unbantu的版本(deb) 解压安装包 tar -zxvf Apache_OpenOffice_4.1.13_Linux_x86-64_install-deb_zh-…

【Hive】【Hadoop】工作中常操作的笔记-随时添加

文章目录 1、Hive 复制一个表:2、字段级操作3、hdfs 文件统计 1、Hive 复制一个表: 直接Copy文件 create table new_table like table_name;hdfs dfs -get /apps/hive/warehouse/ods.db/table_nameload data local inpath /路径 into table new_table;修复表: m…

25.Java程序设计-基于SSM框架的微信小程序校园求职系统的设计与实现

1. 引言 1.1 背景 介绍校园求职系统的背景,说明为什么设计这个系统以及系统的重要性。 1.2 研究目的 阐述设计基于SSM框架的微信小程序校园求职系统的目标和意义。 2. 需求分析 2.1 行业背景 分析校园求职行业的特点和需求,以及目前市场上同类系统…

数据结构-链表习题(C++)

程序设计题: 单链表实验 1.从键盘输入若干大于0的整数,用这些整数构造一个单链表.当用户输入小于等于0的值时创建链表结束并在终端打印输出这个链表。 2.在链表中查找某结点,如果能找到输出这个结点是第几个结点,如果找不到,输出:…

什么是Ajax,Ajax的优点和用处有什么

Ajax(Asynchronous JavaScript and XML)是一种用于创建快速动态网页的技术。它利用JavaScript和XML(现在也可以使用JSON或HTML)来进行异步通信,实现在网页上更新数据而无需重新加载整个页面。 Ajax的优点和用处有以下…

翻译: LLM工具使用和代理Tool use and agents

欢迎来到本周的最后一个视频。在这个视频中,我想与您分享LLM(大型语言模型)开始能够使用工具的情况,以及讨论一下前沿的“代理”主题,这是让LLM自己决定下一步采取什么行动的领域。让我们来看看。在早期的食物订单接收…

【C 剑指offer】有序整型矩阵元素查找 {杨氏矩阵}

目录 题目内容: 思路: 图形演示: 复杂度分析 C源码: /** *************************************************************************** ******************** ********************* ******…

遥感论文 | Scientific Reports | 一种显著提升遥感影像小目标检测的网络!

论文题目:MwdpNet: towards improving the recognition accuracy of tiny targets in high-resolution remote sensing image论文网址:https://www.nature.com/articles/s41598-023-41021-8 摘要 提出MwdpNet,以提高对高分辨率遥感&#xf…