作为一个面试官,我想问问你Redis分布式锁怎么搞?

两盒软妹~` 提交于 2020-08-13 02:37:15
最强面试题推荐:
作为一个面试官,我想问问你Redis分布式锁怎么搞?

总结一下加锁过程:首先选择一台机器,然后发送一段lua脚本,带有三个参数:一个是锁的名字(在代码里指定的)、一个是锁的时常(默认30秒)、一个是加锁的客户端id(每个客户端对应一个id)。然后脚本会判断是否有该名字的锁,如果没有就往数据结构中加入该锁的客户端id。

锁互斥机制

作为一个面试官,我想问问你Redis分布式锁怎么搞?

 

很简单,上面第一个if判断会执行“exists myLock”,如果发现myLock这个锁key已经存在了,就会进行第二个if判断,判断一下myLock锁key的hash数据结构中,是否包含客户端2的ID,但是明显不是的,因为那里包含的是客户端1的ID。

所以,客户端2会获取到pttl myLock返回的一个数字,这个数字代表了myLock这个锁key的剩余生存时间。比如还剩15000毫秒的生存时间。

此时客户端2会进入一个while循环,不停的尝试加锁。直到客户端1释放myLock这个锁。

锁时间自动延迟机制

客户端1加锁的默认时长是30秒,如果超过了30秒,客户端1还想持有这把锁该怎么办呢?机制如下:

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

可重入加锁机制

如果客户端1已经持有这把锁了,还想加锁,该怎么办呢?比如代码逻辑如下:

Rlock lock = redisson.getLock(“myLock”);
lock.lock();
// 一坨代码
lock.lock();
// 一坨代码
lock.unlock();
lock.unlock();

 

这时我们来分析一下上面那段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的数据结构变成了这样:

myLock:
{
    “8743c9c0-0795-4907-87fd-6c719a6b4586:1”:2
}

 

可以看出,后面那个数字表示该id的锁的加锁次数。

锁释放机制

如果执行lock.unlock(),就可以释放分布式锁,此时的业务逻辑也是非常简单的。其实说白了,就是每次都对myLock数据结构中的那个加锁次数减1。如果发现加锁次数是0了,说明这个客户端已经不再持有锁了,此时就会用:“del myLock”命令,从redis里删除这个key。然后呢,另外的客户端2就可以尝试完成加锁了。

这就是Redis分布式锁基于开源Redisson框架的实现机制。

Redis分布式锁的缺点

这种分布式锁最大的缺点在于:如果对某个redis-master实例写入了myLock这个key的锁的value,此时会异步复制数据到redis-slave实例上。

但是在这个过程中发生了redis-master宕机了,主备切换,redis-slave变成了redis-master。

紧接着,客户端2就来尝试加锁,在新的redis-master上加了锁,而此时客户端1也认为自己加了锁,这就导致多个客户端对同一个分布式锁完成了加锁。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!