数据库
首页 > 数据库> > redis实现分布式锁:他说,他的分布式锁,很润哦

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

作者:互联网

在这里插入图片描述

文章目录

什么是分布式锁?

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

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

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

加锁:

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

setnx(lock_sale_商品ID,1)

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

解锁

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

del(lock_sale_商品ID)

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

锁超时

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

expire(lock_sale_商品ID, 30)

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

SETNX

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

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

返回值:

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

原始代码

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

第一把锁


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

···

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

事务操作

redis中销毁key

···

这里加上了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

第三把锁

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

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


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

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

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

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

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


第四把锁

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

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

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

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

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

那不是完蛋???

那怎么办?

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


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

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

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

第五把锁

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

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

续期。

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

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

大家可以自己思考一下。


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

结束语

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

在这里插入图片描述

标签:redis,线程,key,SETNX,values,很润,分布式
来源: https://blog.51cto.com/u_15197573/2772439