当前位置:首页 > 财经

setnx 漫画:什么是分布式锁?

————————————

分布式锁有哪些实现?

1.Memcached分布式锁

使用Memcached的add命令。这个命令是一个原子操作。只有当密钥不存在时,添加才能成功,这意味着线程被锁定。

2.Redis分布式锁

与Memcached类似,使用Redis的setnx命令。这个命令也是原子操作。只有当密钥不存在时,集合才能成功。(setnx命令并不完美,稍后将介绍替代命令。)

3.动物园管理员分布式锁

利用动物园管理员的顺序临时节点,实现了分布式锁和等待队列。Zookeeper最初是为了实现分布式锁服务而设计的。

4.圆胖的

Google的粗粒度分布式锁服务,底层使用Paxos一致性算法。

如何用Redis实现分布式锁?

Redis分布式锁的基本流程并不难理解,但是要写得完美却不是那么容易。在这里,我们需要理解分布式锁实现的三个核心元素:

1.锁

最简单的方法是使用setnx命令。钥匙是锁的唯一标识符,根据业务命名。比如你想锁定一个商品的尖峰活动,可以把钥匙命名为“lock_sale_ commodity ID”。值设置为什么?就设成1吧。锁定的伪代码如下:

setnx(键,1)

当一个线程执行setnx并返回1时,表示密钥原本不存在,线程成功获得锁;当一个线程执行setnx并返回0时,表示key已经存在,线程抢锁失败。

2.用钥匙开锁

有锁就要开锁。当被锁定的线程完成任务时,它需要释放锁,以便其他线程可以进入。释放锁最简单的方法是执行del指令,伪代码如下:

del(键)

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

3.锁定超时

锁超时是什么意思?如果一个被锁定的线程在执行一个任务的过程中挂起,并且显式释放锁已经太晚了,那么这个资源将永远被锁定,其他线程也永远不会再进来。

所以setnx的key必须设置一个超时,以保证锁在一定时间后即使没有明确释放也会自动释放。Setnx不支持超时参数,所以需要额外的指令。伪代码如下:

过期(密钥,30)

总而言之,我们的分布式锁实现的第一个伪代码如下:

if(setnx(key,1)= 1){

过期(密钥,30)

尝试{

做某事......

}最后{

del(键)

}

}

代码结尾不错,怎么回家等通知?

因为上面的伪代码有三个致命的问题:

1.集合NX和过期的非原子性

想象一个极端的场景,当一个线程执行setnx时,它成功地获得了锁:

Setnx刚刚成功执行,但是在它能够执行expire命令之前,节点1 Duang挂起。

这样,锁没有设置到期时间,变成“不死”,其他线程就无法再获得锁。

怎么解决?Setnx指令本身不支持传入超时。幸运的是,REDIS 2 . 6 . 12版或以上版本给set指令增加了可选参数,伪代码如下:

设置(键,1,30,NX)

这样就可以替换setnx命令了。

2.del导致错误删除

另一个极端的情况是,如果一个线程成功获得锁,并且设置的超时时间是30秒。

如果线程A由于某种原因执行缓慢,30秒后没有完成,那么锁过期自动释放,线程B得到锁。

然后,线程a完成执行任务,然后线程a执行del指令释放锁。但此时线程B还没有执行完,线程A实际上删除了线程B添加的锁。

如何避免这种情况?您可以在del释放锁之前进行判断,以验证当前锁是否是自添加的。

至于具体实现,可以在锁定时以当前线程ID为值,在删除前验证key对应的值是否是自己线程的ID。

锁定:

string threadId = thread . Currentthread()。getId()

set(key,threadId,30,NX)

解锁:

if(ThreadId . equals(RedIsclient . get(key))){

del(键)

}

然而,这意味着一个新的问题:判断和释放锁是两个独立的操作,而不是原子性。

我们都是追求完美的程序员,所以这一块应该用Lua脚本来实现:

string LuAscript = " if redis . call(' get ',KEYS[1]) == ARGV[1]然后returnredis.call('del ',KEYS[1])else return 0 end ";

redisClient.eval(lua,Collections.singletonList(key),collections . singletonlist(threadId));

这样,验证和删除过程就是一个原子操作。

3.并发的可能性

在刚才第二点描述的场景中,虽然我们避免了线程A误删键的情况,但是有两个线程A和B同时访问代码块,这还是不完善的。

我该怎么办?我们可以让获得锁的线程打开一个守护线程来“延长”即将到期的锁。

29秒后,线程A还没有执行完。此时,守护线程将执行expire指令来“更新”锁20秒。守护线程从第29秒开始执行,每20秒执行一次。

当线程a完成任务时,它将显式关闭守护线程。

另一方面,如果节点1突然断电,守护线程将停止,因为线程A和守护线程在同一个进程中。锁超时没人续,自动解除。

守护线程的代码不难实现。有了大致的思路,你可以尝试自己去实现。

ID:zxsycjh

1.《setnx 漫画:什么是分布式锁?》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《setnx 漫画:什么是分布式锁?》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/caijing/1014846.html

上一篇

驾驶证换证体检项目 重大福利!东莞司机驾驶证期满换证,体检证明不用再跑医院

下一篇

松花江哈尔滨段所有船舶停航 真相原来是这样!

曼哈顿距离 一行Python代码计算两点间曼哈顿距离

曼哈顿距离 一行Python代码计算两点间曼哈顿距离

以下图为例。图中白色方块表示该建筑不能穿越,只能绕过。然后从左下角开始到右上角,红蓝黄三条路线的距离相等,称为曼哈顿距离,或者实际步行距离。  对于向量(x1,x2,x3,...,xn)和(y1,y2,y3,...,yn)之间空,曼哈顿距离定义为:  使用Python计算曼哈顿距离的代码如下...

深圳海关代码 深圳海关权威发布!金关二期常见问题解答(汇总)

  • 深圳海关代码 深圳海关权威发布!金关二期常见问题解答(汇总)
  • 深圳海关代码 深圳海关权威发布!金关二期常见问题解答(汇总)
  • 深圳海关代码 深圳海关权威发布!金关二期常见问题解答(汇总)
如何打开命令行窗口 CAD命令行不见了,怎么打开?

如何打开命令行窗口 CAD命令行不见了,怎么打开?

CAD命令行缺失,如何打开? 命令行用于输入命令和显示命令参数,如下图所示。  有时候命令行关闭,给操作带来很多麻烦。打开命令行最简单的方法是快捷键:CTRL+9,可以用来关闭或打开命令行。AutoCAD、陈豪CAD等类似软件都使用同一个快捷键。如果使用带有下拉菜单的界面,可以点击下拉菜单中...

王一博微博 我写代码扒了「王一博」5年的微博,竟然发现了这些

  • 王一博微博 我写代码扒了「王一博」5年的微博,竟然发现了这些
  • 王一博微博 我写代码扒了「王一博」5年的微博,竟然发现了这些
  • 王一博微博 我写代码扒了「王一博」5年的微博,竟然发现了这些

sftp命令 如何使用SFTP与Linux服务器之间传输文件?

  • sftp命令 如何使用SFTP与Linux服务器之间传输文件?
  • sftp命令 如何使用SFTP与Linux服务器之间传输文件?
  • sftp命令 如何使用SFTP与Linux服务器之间传输文件?

vhdl 不管是VHDL还是Verilog,要写好都要遵守这25条代码通则

  • vhdl 不管是VHDL还是Verilog,要写好都要遵守这25条代码通则
  • vhdl 不管是VHDL还是Verilog,要写好都要遵守这25条代码通则
  • vhdl 不管是VHDL还是Verilog,要写好都要遵守这25条代码通则
tcpdump 在Linux命令行中使用tcpdump「超详细」

tcpdump 在Linux命令行中使用tcpdump「超详细」

灵活而强大的命令行工具可以帮助减轻排除网络问题的痛苦。 根据我作为系统管理员的经验,我经常发现很难解决网络连接问题。Tcpdump是这些情况下的好朋友。 Tcpdump是一个命令行实用程序,允许捕获和分析通过系统的网络流量。它通常用于帮助解决网络问题,以及安全工具。 Tcpdump是一个功能...

tcpdump命令详解 在Linux命令行中使用tcpdump「超详细」

tcpdump命令详解 在Linux命令行中使用tcpdump「超详细」

灵活而强大的命令行工具可以帮助减轻排除网络问题的痛苦。 根据我作为系统管理员的经验,我经常发现很难解决网络连接问题。Tcpdump是这些情况下的好朋友。 Tcpdump是一个命令行实用程序,允许捕获和分析通过系统的网络流量。它通常用于帮助解决网络问题,以及安全工具。 Tcpdump是一个功能...