Redlock实现Redis分布式锁

注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解!

之前写过《基于JedisLock实现Redis分布式锁》的文章,里面提到思路是通过setNx命令
实现分布式锁的处理。事实上这类琐最大的缺点就是它加锁时只作用在一个Redis节点上,即使Redis通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况:
在Redis的Master节点上拿到了锁,但是这个加锁的key还没有同步到Slave节点,Master故障,发生故障转移,Slave节点升级为Master节点,导致锁丢失。

关于Redis实现分布式锁,Redis官方推荐使用Redlock。里面提到很多的有许多库和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都使用不同的方法,并且许多库使用简单的方法,与稍微复杂的方法相比可以实现更低的保证设计。故提供一种更规范的算法来使用Redis实现分布式锁。简称Redlock的算法。(相关说明这里就不一一说明了,有兴趣的同学自行到官网查看)
官方说明地址:https://redis.io/topics/distlock

一、Redlock实现原理

在算法的分布式版本中,我们假设我们有N个Redis主机。这些节点完全独立,因此我们不使用复制或任何其他隐式协调系统。我们已经描述了如何在单个实例中安全地获取和释放锁。我们理所当然地认为算法将使用此方法在单个实例中获取和释放锁。在我们的示例中,我们设置N = 5,这是一个合理的值,因此我们需要在不同的计算机或虚拟机上运行5个Redis主服务器,以确保它们以大多数独立的方式失败。

为了获取锁,客户端执行以下操作:

  1. 它以毫秒为单位获取当前时间。
  2. 它尝试按顺序获取所有N个实例中的锁,在所有实例中使用相同的键名和随机值。在步骤2期间,当在每个实例中设置锁定时,客户端使用与总锁定自动释放时间相比较小的超时以获取它。例如,如果自动释放时间是10秒,则超时可以在~5-50毫秒范围内。这可以防止客户端长时间保持阻塞,试图与Redis节点进行通信,如果实例不可用,我们应该尝试尽快与下一个实例通话。
  3. 客户端通过从当前时间中减去在步骤1中获得的时间戳来计算获取锁定所需的时间。当且仅当客户端能够在大多数实例中获取锁定时(至少3个)并且获取锁定所经过的总时间小于锁定有效时间,认为锁定被获取。
  4. 如果获得了锁,则其有效时间被认为是初始有效时间减去经过的时间,如步骤3中计算的那样。
  5. 如果客户端由于某种原因(无法锁定N / 2 +
    1实例或有效时间为负)未能获取锁定,它将尝试解锁所有实例(即使它认为不是能够锁定)。

二、Redisson 实现方式

maven依赖

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.10.7</version>
</dependency> 

github地址:https://github.com/redisson/redisson

代码实现

		Config config1=new Config();
        config1.useSingleServer().setAddress("redis://127.0.0.1:6379");
        RedissonClient redisson1 =  Redisson.create(config1);


        Config config2=new Config();
        config2.useSingleServer().setAddress("redis://127.0.0.1:6378");
        RedissonClient redisson2 =  Redisson.create(config2);


        Config config3=new Config();
        config3.useSingleServer().setAddress("redis://127.0.0.1:6377");
        RedissonClient redisson3 =  Redisson.create(config3);

        RLock rLock1=redisson1.getLock("key");
        RLock rLock2=redisson2.getLock("key");
        RLock rLock3=redisson3.getLock("key");

        // 向3个redis实例尝试加锁
        RedissonRedLock redLock = new RedissonRedLock(rLock1,rLock2,rLock3);
        boolean isLock;
        try {
            // 500ms拿不到锁, 就认为获取锁失败。10000ms即10s是锁失效时间。
            isLock = redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS);
            System.out.println("isLock = "+isLock);
            if (isLock) {
                RedissonRedLock redLock2= new RedissonRedLock(rLock1,rLock2,rLock3);
                isLock=redLock2.tryLock(500, 10000, TimeUnit.MILLISECONDS);
                System.out.println("isLock = "+isLock);
                redLock2.unlock();
            }
        } catch (Exception e) {

        } finally {
            // 无论如何, 最后都要解锁
            redLock.unlock();
        }

注:这里是作最简单的实现,更多示例可以查看git相关示例

1、Redission实现分布式锁(官网推荐)
https://blog.csdn.net/weixin_43947588/article/details/90064064
2、Curator基于zookeeper实现分布式锁
https://blog.csdn.net/weixin_43947588/article/details/84893777
3、Jedis实现分布式锁
https://blog.csdn.net/weixin_43947588/article/details/98631392

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值