前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >redis实现分布式锁:他说,他的分布式锁,很润哦

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

作者头像
看、未来
发布2020-09-15 10:06:33
4320
发布2020-09-15 10:06:33
举报

什么是分布式锁?

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

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

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

加锁:

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

代码语言:javascript
复制
setnx(lock_sale_商品ID,1)

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

解锁

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

代码语言:javascript
复制
del(lock_sale_商品ID)

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

锁超时

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

代码语言:javascript
复制
expire(lock_sale_商品ID, 30)

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

SETNX

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

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

返回值:

代码语言:javascript
复制
   1 如果key被设置了
    0 如果key没有被设置

原始代码

代码语言:javascript
复制
····
事务实现(比方说:扣除库存)
····

第一把锁

代码语言:javascript
复制
string key = "key";
string values = "values";

···

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

事务操作

redis中销毁key

···

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

第二把锁

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

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

代码语言:javascript
复制
string key = "key";
string values = "values";

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

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

第三把锁

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

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

代码语言:javascript
复制
string key = "key";
string values = "values";

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

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

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

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

第四把锁

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

代码语言:javascript
复制
线程A:拿到锁,执行15秒,在第10秒的时候,锁被redis给释放掉了。

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

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

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

那不是完蛋???

那怎么办?

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

代码语言:javascript
复制
string key = "key";
string values = 专属随机值;

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

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

第五把锁

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

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

续期。

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

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

大家可以自己思考一下。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是分布式锁?
    • 通过 Redis 分布式锁的实现理解基本概念
      • 加锁:
      • 解锁
      • 锁超时
  • redis分布式锁实现及各种问题解析
    • SETNX
      • 原始代码
        • 第一把锁
          • 第二把锁
            • 第三把锁
              • 第四把锁
                • 第五把锁
                相关产品与服务
                云数据库 Redis
                腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档