Redis分布式锁实现Redisson 15问(六)

pivoteic
发布于 2022-6-20 17:39
浏览
0收藏

 

十四、Redis分布式锁存在的问题

 

对于单Redis实例来说,如果Redis宕机了,那么整个系统就无法工作了。所以为了保证Redis的高可用性,一般会使用主从或者哨兵模式。但是如果使用了主从或者哨兵模式,此时Redis的分布式锁的功能可能就会出现问题。

 

举个例子来说,假如现在使用了哨兵模式,如图。

Redis分布式锁实现Redisson 15问(六)-鸿蒙开发者社区

基于这种模式,Redis客户端会在master节点上加锁,然后异步复制给slave节点。

 

但是突然有一天,因为一些原因,master节点宕机了,那么哨兵节点感知到了master节点宕机了,那么就会从slave节点选择一个节点作为主节点,实现主从切换,如图:

Redis分布式锁实现Redisson 15问(六)-鸿蒙开发者社区

这种情况看似没什么问题,但是不幸的事发生了,那就是客户端对原先的主节点加锁,加成之后还没有来得及同步给从节点,主节点宕机了,从节点变成了主节点,此时从节点是没有加锁信息的,如果有其它的客户端来加锁,是能够加锁成功的,这不是很坑爹么。。

 

那么如何解决这种问题呢?Redis官方提供了一种叫RedLock的算法,Redisson刚好实现了这种算法,接着往下看。

 

十五、如何实现RedLock算法

 

RedLock算法

 

在Redis的分布式环境中,我们假设有N个Redis master。这些节点完全互相独立,不存在主从复制或者其他集群协调机制。之前我们已经描述了在Redis单实例下怎么安全地获取和释放锁。我们确保将在每(N)个实例上使用此方法获取和释放锁。在这个样例中,我们假设有5个Redis master节点,这是一个比较合理的设置,所以我们需要在5台机器上面或者5台虚拟机上面运行这些实例,这样保证他们不会同时都宕掉。

 

为了取到锁,客户端应该执行以下操作:

 

  1. 获取当前Unix时间,以毫秒为单位。
  2. 依次尝试从N个实例,使用相同的key和随机值获取锁。在步骤2,当向Redis设置锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。
  3. 客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数(这里是3个节点)的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。
  4. 如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。
  5. 如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。

 

Redisson对RedLock算法的实现

 

使用方法如下。

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
 
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
...
lock.unlock();

 

RedissonRedLock加锁过程如下:

  • 获取所有的redisson node节点信息,循环向所有的redisson node节点加锁,假设节点数为N,例子中N等于5。一个redisson node代表一个主从节点。
  • 如果在N个节点当中,有N/2 + 1个节点加锁成功了,那么整个RedissonRedLock加锁是成功的。
  • 如果在N个节点当中,小于N/2 + 1个节点加锁成功,那么整个RedissonRedLock加锁是失败的。
  • 如果中途发现各个节点加锁的总耗时,大于等于设置的最大等待时间,则直接返回失败。

 

RedissonRedLock底层其实也就基于RedissonMultiLock实现的,RedissonMultiLock要求所有的加锁成功才算成功,RedissonRedLock要求只要有N/2 + 1个成功就算成功。

Redis分布式锁实现Redisson 15问(六)-鸿蒙开发者社区

参考:

[1]. https://mp.weixin.qq.com/s/EhucmYblfrRxbAuJTdPlfg
[2]https://github.com/redisson/redisson/wiki/
[3]http://redis.cn/topics/distlock.html

 

 

文章转自公众号:三友的java日记

标签
已于2022-6-20 17:39:22修改
收藏
回复
举报
回复
    相关推荐