Redis 分布式锁_set ex px nx-程序员宅基地

技术标签: Redis  分布式  redis  

Redis 系列笔记:

第一篇:Redis 基础命令
第二篇:Redis 常见应用场景
第三篇:Redis Cluster集群搭建
第四篇:Redis 主从及哨兵搭建
第五篇:Redis 主从及集群
第六篇:Redis 持久化
第七篇:Redis 分布式锁
第八篇:Redis 底层数据存储结构
第九篇:Redis 面试常问问题



前言

Redis分布式锁应用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、为什么需要分布式锁

因为Redis分布式环境中所有的服务器都可以向Redis发送写入命令,且只有一个可以写入命令成功,那么这个写入命令成功的服务器即获得了锁,可以进行后续对资源的操作,其他未写入成功的服务,则进行其他处理。为了保证一个方法在高并发情况下的同一时间只能被同一个线程执行,才需要分布式锁。


二、分布式锁具备哪些条件

互斥性:锁的目的是获取资源的使用权,所以任意时刻只让一个客户端持有锁,这一点要尽可能保证;只有一个客户端能持有锁。
安全性:锁只能被持有的客户端删除,不能被其他客户端删除
锁失效机制:避免死锁情况发生。当一个客户端在持有锁期间内,由于意外崩溃而导致未能主动解锁,其持有的锁也能够被正常释放,并保证后续其它客户端也能加锁;
可重入性:当一个客户端获取了锁之后,可以再次对其请求加锁。
高性能和高可用:加锁和解锁需要开销尽可能低,同时也要保证高可用,避免分布式锁失效。
可靠性:需要有一定程度的异常处理能力、容灾能力。


三、实现分布式锁的几种方法

1. 单实例分布式锁

setnx: 如果key不存在,则会将key设置为value,并返回1;如果key存在,不会有任务影响,返回0。

两种简单使用方法:

1、set 时加上 nxex|px 参数
2、setnx + expire 组合。

1. SET NX EX|PX

和下面使用LUA 脚本一样,SET NX EX|PX是一个原子性操作。虽然是原子性操作,但也有可能会出现下面这种情况:

由于网路延迟导等原因致业务还没执行完,锁就过期释放了。这时其他进程来获取锁,获取成功,但是之前的业务代码还没有执行完导致数据异常。

对于锁过期释放,业务没执行完的问题,redisson框架解决了这个问题。redisson 是 redis 官方的分布式锁组件。上面的这个问题 ——> 失效时间设置多长时间为好?这个问题在 redisson 的做法是:每获得一个锁时,只设置一个很短的超时时间,同时起一个线程【watch dog看门狗】,它是一个后台线程,在每次快要到超时时间时去刷新锁的超时时间。在释放锁的同时结束这个线程。

2. SETNX + EXPIRE

先用 setnx 来抢锁,如果抢到之后,再用 expire 给锁设置一个过期时间,防止锁忘记了释放。但是这个方案中,setnxexpire 两个命令分开了,「不是原子操作」。如果执行完setnx加锁,正要执行expire设置过期时间时,服务重启维护了,那么这个锁就变成死锁了。

为了解决上面的这种死锁的情况,这里提供了两种解决方法:

1、setnx 设置的value值是系统时间+过期时间。如果加锁失败,再拿出value值校验一下。当前做法需要注意:

  • 分布式环境下,每个客户端的时间必须同步
  • 如果锁过期的时候,并发多个客户端同时请求过来,最终只能有一个客户端加锁成功,但是该客户端锁的过期时间,可能被别的客户端覆盖。
  • 该锁没有保存持有者的唯一标识,可能被别的客户端释放/解锁。(可以设置一个标记当前线程唯一的随机数,删除时验证)
     

2、使用 LUA 脚本来保证原子性

2. 多机实现的分布式锁

当客户端A 在Redis的master节点上拿到了锁,但是加锁的key还没同步到slave节点。恰好这时,master节点发生故障,一个slave节点就会升级为master节点。客户端B 就可以获取同个key的锁,但客户端A 也已经拿到锁了,锁的安全性就没了。

1. Redlock

为了解决这个问题,Redis作者 antirez提出一种高级的分布式锁算法:Redlock。RedLock的实现步骤:如下:

1、获取当前时间,以毫秒为单位。
 
2、按顺序向5个master节点请求加锁。客户端设置网络连接和响应超时时间,并且超时时间要小于锁的失效时间。如果超时,跳过该master节点,尽快去尝试下一个master节点。

  • 比如:TTL(失效时间)为5s,设置获取锁最多用1s(请求所有master时间和),所以如果一秒内无法获取锁,就放弃获取这个锁,从而尝试获取下个锁
     

3、用客户端获取所有能获取的锁后的时间减去开始获取锁时间(即步骤1记录的时间),得到获取锁使用的时间。当且仅当超过一半(N/2+1)的Redis master节点都获得锁,并且使用的时间小于锁失效时间时,锁才算获取成功。
 

4、.如果成功获取锁,则锁的真正有效时间是 TTL减去第三步的时间差 的时间;

  • 比如:TTL 是5s,获取所有锁用了1s,则真正锁有效时间为4s(其实应该再减去时钟漂移【系统时间重新对时或者被修改】,可以给 watch dog 间隔时间延长,可以极大概率上解决问题);

 
5、如果获取锁失败(获取到锁的master实例至少N/2+1个,有或者获取锁时间已经超过了有效时间),客户端要在所有的master节点上解锁(即便有些master节点根本就没有加锁成功,也需要解锁,以防止有些漏网之鱼)。

具体使用存在争议,不太推荐使用。Redisson 的开发者认为 Redis 的红锁也存在争议(参考下面链接),但是为了保证可用性,RLock 对象执行的每个 Redis 命令执行都通过 Redis 3.0 中引入的 WAIT 命令进行同步。
WAIT 命令会阻塞当前客户端,直到所有以前的写命令都成功的传输并被指定数量的副本确认。如果达到以毫秒为单位指定的超时,则即使尚未达到指定数量的副本,该命令也会返回。 WAIT 命令同步复制也并不能保证强一致性,不过在主节点宕机之后,只不过会尽可能的选择最佳的副本(slaves)。如果考虑高可用并发推荐使用Redisson,考虑一致性推荐使用zookeeper。

Redisso争议参考:Redisson 分布式锁源码 09:RedLock 红锁的故事

2. zookeeper

参考:Redis实现分布式锁


总结

在极端的情况下,都会有锁失效或锁冲突的情况出现,建议对分布式锁不要强依赖,没有绝对可靠的分布式锁,分布式锁需要与业务的联动配合更加切实可行,不要造成不必要的损失。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43844718/article/details/126463959

智能推荐

ZZUIL题解1061-1070_下积无1067ac-程序员宅基地

文章浏览阅读547次。有疑问的地方请在下方处评论1061:顺序输出各位数字1062: 最大公约数1063:最大公约与最小公倍1064: 加密字符1065: 统计数字字符的个数1066: 字符分类统计1067: 有问题的里程表1068:二进制数1069: 向Z同学学习1070: 小汽车的位置1061:顺序输出各位数字题目描述 输入一个不大于10的9次方的正整数,从高位开始逐位分割并输出各位数字。 输入输入一个正整数n,n是int型数据输出依次输出各位上的数字,每一个数字后面有一个空格,输出占一行。_下积无1067ac

Android 自定义 View:饼图/扇形图(PieView)_自定义view绘制扇形图片-程序员宅基地

文章浏览阅读2.7k次,点赞5次,收藏7次。前两天看到朱凯大神发表了酝酿一整年的新作:《HenCoder:给高级 Android 工程师的进阶手册》,作为一个码农不敢妄看高级之物,但看在朱凯大神久处于朱大嫂淫威之下,关顾一下以示支持,不曾想到大神的文章是以细微处见真知,回到基础知识上,真是久旱逢甘露,挣扎已久的心突然静了下来,慢慢找回“多敲代码少BiBi”的正经路上…_自定义view绘制扇形图片

使用iconv进行内码转换(Big5->GB2312) -程序员宅基地

文章浏览阅读479次。iconv是一个通过unicode作为中间码实现各种内码间相互转换的库,它基本上囊括了世界上所有编码方式,例如,ASCII、 GB2312、 GBK、 GB18030、BIG5、UTF-8、UCS-2、UCS-2BE、UCS-2LE、UCS-4、UCS-4BE、UCS- 4LE、UTF-16、 UTF-16BE、UTF-16..._iconv utf16 utf32

hadoop的四个核心配置文件详解_简述配置hadoop需要修改的xml文件是哪些?-程序员宅基地

文章浏览阅读9.9k次,点赞5次,收藏44次。https://blog.csdn.net/cuitaixiong/article/details/51591410hadoop常用端口配置1.HDFS 端口参数描述默认配置文件例子值fs.default.namenamenode RPC交互端口8020core-site.xmlhdfs://master:8020/dfs.http.address..._简述配置hadoop需要修改的xml文件是哪些?

详解活动图计算关键路径、最早开始时间、最晚开始时间、冗余时间,C++ 程序实现_活动图最早开始时间-程序员宅基地

文章浏览阅读2.6w次,点赞49次,收藏110次。题目下图是一个软件开发项目的活动图,对于图中每条边的数字表示完成这条边代表的活动的天数。例如,完成终止于里程碑E的活动需要 4 天时间。对于每个活动,列出它的前驱,并计算最早开始时间、最晚开始时间和时差,然后确定出关键路径。—— 《软件工程 第 4 版》中的原题写文缘由网上的文章大都是对于 “点” 求最早开始时间和最晚开始时间。在我看来,是不准确的。对于边的解法,有的写得又太复杂,还是自己写吧。误区在哪需要注意的是,图中的点,并不代表活动,并不能说活动 AAA 用 333 天到达活动 _活动图最早开始时间

Windows环境下通过Xshell发送文件到远程Linux主机_windows环境变量可以发给linux 通过xming-程序员宅基地

文章浏览阅读278次。windows与linux之间的中小型文件传递可以使用sz、rz命令来实现sz:将linux主机中选定的文件发送到windows主机。rz:执行该命令会弹出一个文件选择窗口,从windows主机选择文件发送到linux主机。首先检查linux主机上有没有安装lrzsz。如果已按照会显示按照的版本,如果没有安装不会有任何显示。(以下为已安装)[root]# yum list i..._windows环境变量可以发给linux 通过xming

随便推点

【python初级】 ModuleNotFoundError: No module named paho_modulenotfounderror: no module named 'paho-程序员宅基地

文章浏览阅读8.2k次,点赞3次,收藏3次。【python初级】 ModuleNotFoundError: No module named paho1、背景2、解决1、背景python3在导入mqtt时报错,具体如下:Traceback (most recent call last): File "E:/E05_Project/mqtt_server.py", line 17, in <module> import paho.mqtt.client as mqttModuleNotFoundError: No modu_modulenotfounderror: no module named 'paho

fatal error: opencv2/freetype.hpp: 没有那个文件或目录 - opencv_contrib_没有 opencv2/freetype.hpp-程序员宅基地

文章浏览阅读5.1k次。fatal error: opencv2/freetype.hpp: 没有那个文件或目录 - opencv_contrib1. freetype.hpp fileopencv2https://docs.opencv.org/4.2.0/dc/d8f/freetype_8hpp.htmlopencv_contrib -> modules -> freetype -> include -> opencv2https://docs.opencv.org/3.2.0/dc/d8f/_没有 opencv2/freetype.hpp

ijkplayer源码分析 FrameQueue分析_rindex_shown-程序员宅基地

文章浏览阅读354次。ijkplayer源码分析 FrameQueue分析_rindex_shown

MATLAB实现Lagrange插值函数_matlab lagrange-程序员宅基地

文章浏览阅读1.8w次,点赞24次,收藏76次。MATLAB实现Lagrange插值函数首先我们绘制Lagrange基函数首先给出一个Lagrange基函数比较复杂的设法:function y=lagrange(x0,y0,x)n=length(x0);m=length(x);for i=1:m z=x(i); s=0.0; for k=1:n p=1.0; for j=1:n if j~=k p = p*(z-x0(j))/(x0_matlab lagrange

Jenkins拉取Gitlab项目代码配置SSH Keys步骤_jenkins git ssh key-程序员宅基地

文章浏览阅读7.3k次,点赞3次,收藏10次。Jenkins容器生成秘钥进入目录:cd ~/.ssh如果没有该目录就创建:mkdir -p ~/.ssh生成秘钥:ssh-keygen -t rsa -C “登录gitlab的邮箱”查看对应的ssh-keyjenkins@f050d7fa04f0:~/.ssh$ lsid_rsa id_rsa.pubid_rsa.pub:公钥,复制到gitlab平台配置ssh-keyid_rsa:私钥,复制到jenkins平台配置jenkins凭据拷贝id_rsa.pub到gitlab配置ssh-_jenkins git ssh key

使用git命令时,系统报错:bash: git: command not found...-程序员宅基地

文章浏览阅读6.9k次。使用git命令时,系统报错:bash: git: command not found…原因:服务器没有安装git导致系统报错解决方法:(Centos7)yum install -y git 执行命令安装git后即可解决_bash: git: command not found...

推荐文章

热门文章

相关标签