✅Redis实现分布锁的时候,哪些问题需要考虑?

典型回答

这是一个比较典型的关于Redis分布式锁的综合性问题,其实考察的就是关于分布式锁的熟悉程度,尤其是Redis的分布式锁的熟悉程度。

我总结了一下关于这个问题可以回答的几个方向和关键点。

锁的基本要求

一个分布式锁有很多基本要求,比如说锁的互斥性可重入性锁的性能等问题。

对于锁的互斥性,可以借助setnx来保证,因为这个操作本身就是一个原子性操作,并且结合Redis的单线程的机制,就可以保证互斥性。

✅Redis中的setnx命令为什么是原子性的

因为Redis是基于内存的,所以他的性能也是很高的,这个就没啥好说的了,大家都知道的。

✅Redis为什么这么快?

至于可重入性,其实就是说一个线程,在锁没有释放的情况下,他是可以反复的拿到同一把锁的。并且需要在锁中记录加锁次数,用来保证重入几次就需要解锁几次。用setnx也是可以实现的。

✅如何用setnx实现一个可重入锁?

当然,如果我们直接使用Redisson的话,他是支持可重入锁的实现的。可以直接用。

✅如何用Redisson实现分布式锁?

误解锁问题

其实就是要确保只有锁的持有者能释放锁,避免其他客户端误解锁。这个问题其实挺傻的,但是我们实际就发生过,因为有的时候我们是在finally中去释放锁,finally有一定会执行,那么就可能会导致虽然没拿到锁,但是当他执行finally的时候,也可能把锁给解了。

所以,需要解决这个问题,我们就需要在使用setnx加锁时把具体持有锁的owner放进去,和上面一样,线程ID也好,业务单号也好,总之需要做一下判断。

如果用了Redisson是不存在这个问题的。

锁的有效时间

为了避免死锁,我们一般会给一个分布式锁设置一个超时时间,如上面我们用的setnx的方案,其实就是设置了一个超时时间的。

但是有的是,代码如果执行的比较慢的话,比如设置的超时时间是3秒,但是代码执行了5秒,那么就会导致在第三秒的时候,key超时了就自动解锁了,那么其他的线程就可以拿到锁了,这时候就会发生并发的问题了。

所以,我们需要有一个好的办法来解决。一种是设置一个更长的超时时间,避免提前释放,我见过有人把分布式锁设置半个小时。。。

但是这个方案非常不好,因为分布式锁是影响并发的,锁的时间长,意味着加锁时间段内只能有一个线程操作,那么并发度就会大大降低。(因为要考虑到解锁失败的问题)

还有一个好的办法,就是像redisson一样,实现一个watch dog的机制,给锁自动做续期,让锁不会提前释放。

✅Redisson的watch dog机制是怎么样的?

但是需要注意的是,只有我们没有自己主动设置锁的超时时间的时候,watchdog才会续期,如果自己设置了超时时间,那么就不会给你续期了。具体看上面这个原理解读。

单点故障问题

有了自动续期之后,锁就一定可靠了吗?其实也不是,这里会存在两个单点问题。

首先,在使用单节点Redis实现分布式锁时,如果这个Redis实例挂掉,那么所有使用这个实例的客户端都会出现无法获取锁的情况。

这个问题是有解的,就是引入集群模式,通过哨兵检测redis实例挂掉的情况,提升整个集群的可用性。

✅介绍一下Redis的集群模式?

但是,这个方案同样存在一个单点故障带来的问题:

当使用集群模式部署的时候,如果master一个客户端在master节点加锁成功了,然后没来得及同步数据到其他节点上,他就挂了, 那么这时候如果选出一个新的节点,再有客户端来加锁的时候,就也能加锁成功,因为数据没来得及同步,新的master会认为这个key是不存在的。

为了解决这个问题,redis的作者提出了一个算法——RedLock,他通过这种算法来保证在半数以上加锁成功才认为成功,这样就可以确保即使master挂了,新选出来的master也会有之前的加锁数据。

具体原理见:

✅什么是RedLock,他解决了什么问题?

网络分区问题

但是,引入红锁就万事大吉了么。也并不是。红锁同样存在问题。首先就是一个网络分区的问题。

在网络分区的情况下,比如集群发生了脑裂,不同的节点可能会获取到相同的锁,这会导致分布式系统的不一致性问题。

✅介绍下Redis集群的脑裂问题?

但是我们需要注意的是,这个情况虽然会存在节点获取到相同锁,但这种情况只会发生在网络分区发生时,且只会发生在一小部分节点上。而在网络分区恢复后,RedLock 会自动解锁。所以理论上来说是有这个风险,但是实际上来说发生的概率极低。

时间漂移问题

除了脑裂,还有一个时钟飘逸的问题,由于不同的机器之间的时间可能存在微小的漂移,这会导致锁的失效时间不一致,也会导致分布式系统的不一致性问题。

那么就会导致有的redis实例已经解锁了,那么就会使得新的客户端可以拿到锁。

这个问题的解决方案是,RedLock 可以使用 NTP 等工具来同步不同机器之间的时间,从而避免时间漂移导致的问题。

原文: https://www.yuque.com/hollis666/xkm7k3/zrney050xgem0voc