redis实现分布式锁:他说,他的分布式锁,很润哦

举报
看,未来 发表于 2020/12/29 22:57:10 2020/12/29
【摘要】 文章目录 什么是分布式锁?通过 Redis 分布式锁的实现理解基本概念加锁:解锁锁超时 redis分布式锁实现及各种问题解析SETNX原始代码第一把锁第二把锁第三把锁第四把锁第五把锁 结束语 什么是分布式锁? 为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布...

在这里插入图片描述

什么是分布式锁?

为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。

通过 Redis 分布式锁的实现理解基本概念

分布式锁实现的三个核心要素:

加锁:

最简单的方法是使用 setnx 命令。key 是锁的唯一标识,按业务来决定命名。比如想要给一种商品的秒杀活动加锁,可以给 key 命名为 “lock_sale_商品ID” 。而 value 设置成什么呢?我们可以姑且设置成 1。加锁的伪代码如下:

setnx(lock_sale_商品ID,1
 
  • 1

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

解锁

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

del(lock_sale_商品ID)

  
 
  • 1

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

锁超时

锁超时是什么意思呢?如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资源将会永远被锁住(死锁),别的线程再也别想进来。所以,setnx 的 key 必须设置一个超时时间,以保证即使没有被显式释放,这把锁也要在一定时间后自动释放。setnx 不支持超时参数,所以需要额外的指令,伪代码如下:

expire(lock_sale_商品ID, 30
 
  • 1

redis分布式锁实现及各种问题解析

SETNX

我们可以用SETNX这条命令轻松的实现一个redis的分布式锁。
什么是SETNX呢?如果还有不明白的,先扫个盲:

将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not
eXists”的简写。

返回值:

   1 如果key被设置了 0 如果key没有被设置

  
 
  • 1
  • 2

原始代码

····
事务实现(比方说:扣除库存)
····

  
 
  • 1
  • 2
  • 3

第一把锁


string key = "key";
string values = "values";

···

bool result = 调用SETNX(key,values);
if(!result)
	return;

事务操作

redis中销毁key

···

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这里加上了result这把锁,当一个线程拿到了这把锁,其他线程的result就全部为0,阻塞。


第二把锁

上面这把锁,存在一些bug。来我们一个一个看。

如果在事务操作的过程中,卡了,会怎么样?那这把锁不就永远的死锁了!!!
那怎么办?
对,try···finally···


string key = "key";
string values = "values";

try{
	bool result = 调用SETNX(key,values);
	if(!result)
		return;

	事务操作
}catch(){
	redis中销毁key
}
redis中销毁key

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

第三把锁

好,抛异常的问题解决了,那如果我现在直接整个线程挂了呢?
那怎么办?
这个try也就没办法了。

对,给这个锁设置一个超时时间。
别忘了啊,究根结底,这个锁它就是个键。


string key = "key";
string values = "values";

try{
	bool result = 配置一个有时限的SETNX锁;	//在redis下有个操作,将SETNX和生命期配置两个原子操作合二为一
	if(!result)
		return;

	事务操作
}catch(){
	redis中销毁key
}
redis中销毁key

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

好,解决一般的分布式锁,到这里已经OK了。

但是,那个男人说,他的分布式锁,很润


第四把锁

有没有想过,你上面那把锁,设置了10秒,如果突然来了个任务,执行了十五秒。那就出问题了。

线程A:拿到锁,执行15秒,在第10秒的时候,锁被redis给释放掉了。

线程B:锁已经被释放,拿锁,执行8秒,但是在执行到第五秒的时候,,,,锁被线程A给释放了哈哈哈哈哈哈

线程C:不说了,运气不好又被别的线程把他的锁给放了。。。。


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在高并发的场景下,后台线程进度根本不可控!!!

那不是完蛋???

那怎么办?

给每一把锁的values,配置上自己线程的专属id,当解锁的时候去看看是不是自己的锁,别把别人的给解了


string key = "key";
string values = 专属随机值;

try{
	bool result = 配置一个有时限的SETNX锁;	//在redis下有个操作,将SETNX和生命期配置两个原子操作合二为一
	if(!result)
		return;

	事务操作
}catch(){
	redis中销毁key
}
redis中,根据values,销毁key

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

第五把锁

第四把锁其实已经很好了,但是还有一个问题遗留,是吧,那把超时的锁,终究是个问题。

那怎么办?设置60秒?设置90秒?
设置多少为合适?多少都不合适,长了阻塞。

续期。

只要加锁成功,就开一个分线程,分线程中加个定时器,每过10秒检查一下那把锁还在不在,那个线程还在不在,要是还在,就给它续期到30秒。

这把锁其实我不是很喜欢,真要这样续期,那当前面几把锁的积累都是摆设吗?

大家可以自己思考一下。


今天就先到这里啦,中午还约了小姐姐吃饭

结束语

建议收藏哦,因为,相见即是缘分,划着划着,就找不着了。

在这里插入图片描述

文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。

原文链接:lion-wu.blog.csdn.net/article/details/108543510

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。