栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Redisson实现Redis分布式锁的底层原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Redisson实现Redis分布式锁的底层原理

一、原理图

二、加锁机制

咱们来看上面那张图,现在某个线程要加锁。如果该线程面对的是一个redis cluster集群,他首先会根据hash节点选择一台机器。

紧接着,就会发送一段lua脚本到redis上,那段lua脚本如下所示:

为啥要用lua脚本呢?

因为一大坨复杂的业务逻辑,可以通过封装在lua脚本中发送给redis,保证这段复杂业务逻辑执行的原子性。

这段lua脚本是什么意思呢?

KEYS[1]: 代表的是你加锁的那个key。

RLock lock = redisson.getLock(“myLock”);这里你自己设置了加锁的那个锁key就是“myLock”

ARGV[1]: 代表的就是锁key的默认生存时间,默认30秒。

ARGV[2]: 代表的是加锁的客户端的ID,类似于下面这样:
8743c9c0-0795-4907-87fd-6c719a6b4586:1

给大家解释一下,第一段if判断语句,就是用“exists myLock”命令判断一下,如果你要加锁的那个锁key不存在的话,你就进行加锁。

如何加锁呢?很简单,用下面的命令:
hset myLock
8743c9c0-0795-4907-87fd-6c719a6b4586:1 1

通过这个命令设置一个hash数据结构,这行命令执行后,会出现一个类似下面的数据结构:

上述就代表“8743c9c0-0795-4907-87fd-6c719a6b4586:1”这个客户端对“myLock”这个锁key完成了加锁。接着会执行“pexpire myLock 30000”命令,设置myLock这个锁key的生存时间是30秒。到此为止,ok,加锁完成了。

三、锁互斥机制

此时,线程2来尝试进行加锁,执行同样的一段lua脚本,会如何?

第一个if判断会执行“exists myLock”,发现myLock这个锁key已经存在了。接着第二个if判断,判断一下,myLock锁key的hash数据结构中,是否包含线程2的ID,但是明显不是的,因为那里包含的是线程1的ID。因此,线程2会获取到pttl myLock返回的一个数字,这个数字代表了myLock这个锁key的剩余生存时间。比如还剩15000毫秒的生存时间。此时线程2会进入一个while循环,不停的尝试加锁。

四、watch dog自动延期机制

线程1加锁的锁key默认生存时间才30秒,如果超过了30秒,线程1还想一直持有这把锁,怎么办呢?

只要客户端1一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。

五、可重入加锁机制

例如下面这段代码:

来分析一下上面那段lua脚本:

第一个if判断肯定不成立,“exists myLock”会显示锁key已经存在了。

第二个if判断会成立,因为myLock的hash数据结构中包含的那个ID,就是客户端1的那个ID,也就是“8743c9c0-0795-4907-87fd-6c719a6b4586:1”

此时就会执行可重入加锁的逻辑,他会用:
incrby myLock
8743c9c0-0795-4907-87fd-6c71a6b4586:1 1
通过这个命令,对客户端1的加锁次数,累加1。

此时myLock数据结构变为下面这样:
8743c9c0-0795-4907-87fd-6c71a6b4586:1 2

六、释放锁机制

释放锁的步骤主要分三步:

1、删除锁(这里注意可重入锁,在上面的脚本中有详细分析)。

2、广播释放锁的消息,通知阻塞等待的进程(向通道名为 redisson_lock__channel publish 一条 UNLOCK_MESSAGE 信息)。

3、取消 Watch Dog 机制,即将 RedissonLock.EXPIRATION_RENEWAL_MAP 里面的线程 id 删除,并且 cancel 掉 Netty 的那个定时任务线程。

七、方案优点

1、Redisson 通过 Watch Dog 机制很好的解决了锁的续期问题。

2、和 Zookeeper 相比较,Redisson 基于 Redis 性能更高,适合对性能要求高的场景。

3、通过 Redisson 实现分布式可重入锁,比原生的 SET mylock userId NX PX milliseconds + lua 实现的效果更好些,虽然基本原理都一样,但是它帮我们屏蔽了内部的执行细节。

4、在等待申请锁资源的进程等待申请锁的实现上也做了一些优化,减少了无效的锁申请,提升了资源的利用率。

八、方案缺点

1、使用 Redisson 实现分布式锁方案最大的问题就是如果你对某个 Redis Master 实例完成了加锁,此时 Master 会异步复制给其对应的 slave 实例。但是这个过程中一旦 Master 宕机,主备切换,slave 变为了 Master。接着就会导致,客户端 2 来尝试加锁的时候,在新的 Master 上完成了加锁,而客户端 1 也以为自己成功加了锁,此时就会导致多个客户端对一个分布式锁完成了加锁,这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。所以这个就是 Redis Cluster 或者说是 Redis Master-Slave 架构的主从异步复制导致的 Redis 分布式锁的最大缺陷(在 Redis Master 实例宕机的时候,可能导致多个客户端同时完成加锁)。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/287594.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号