文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Redis分布式锁之红锁的实现

2022-08-09 13:00

关注

一、问题

分布式锁,当我们请求一个分布式锁的时候,成功了,但是这时候slave还没有复制我们的锁,masterDown了,我们的应用继续请求锁的时候,会从继任了master的原slave上申请,也会成功。

这就会导致,同一个锁被获取了不止一次。

二、办法

Redis中针对此种情况,引入了红锁的概念。

三、原理

用Redis中的多个master实例,来获取锁,只有大多数实例获取到了锁,才算是获取成功。具体的红锁算法分为以下五步:

四、实战

Redission就实现了红锁算法,使用的步骤如下:

1、引入maven

<!-- JDK 1.8+ compatible -->
<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.9.0</version>
</dependency> 

2、引入代码

Config config1 = new Config();
config1.useSingleServer().setAddress("redis://172.0.0.1:5378").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient1 = Redisson.create(config1);

Config config2 = new Config();
config2.useSingleServer().setAddress("redis://172.0.0.1:5379").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient2 = Redisson.create(config2);

Config config3 = new Config();
config3.useSingleServer().setAddress("redis://172.0.0.1:5380").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient3 = Redisson.create(config3);


RLock lock1 = redissonClient1.getLock(lockKey);
RLock lock2 = redissonClient2.getLock(lockKey);
RLock lock3 = redissonClient3.getLock(lockKey);


RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);

try {
  
  boolean res = redLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);
  if (res) {
    //成功获得锁,在这里处理业务
  }
} catch (Exception e) {
  throw new RuntimeException("aquire lock fail");
}finally{
  //无论如何, 最后都要解锁
  redLock.unlock();
}

3、核心源码

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
  long newLeaseTime = -1;
  if (leaseTime != -1) {
    newLeaseTime = unit.toMillis(waitTime)*2;
  }
 
  long time = System.currentTimeMillis();
  long remainTime = -1;
  if (waitTime != -1) {
    remainTime = unit.toMillis(waitTime);
  }
  long lockWaitTime = calcLockWaitTime(remainTime);
  
  int failedLocksLimit = failedLocksLimit();
  
  List<RLock> acquiredLocks = new ArrayList<>(locks.size());
  for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {
    RLock lock = iterator.next();
    boolean lockAcquired;
    
    try {
      if (waitTime == -1 && leaseTime == -1) {
        lockAcquired = lock.tryLock();
      } else {
        long awaitTime = Math.min(lockWaitTime, remainTime);
        lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);
      }
    } catch (RedisResponseTimeoutException e) {
      // 如果抛出这类异常,为了防止加锁成功,但是响应失败,需要解锁所有节点
      unlockInner(Arrays.asList(lock));
      lockAcquired = false;
    } catch (Exception e) {
      // 抛出异常表示获取锁失败
      lockAcquired = false;
    }
   
    if (lockAcquired) {
      
      acquiredLocks.add(lock);
    } else {
      
      if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {
        break;
      }

      if (failedLocksLimit == 0) {
        unlockInner(acquiredLocks);
        if (waitTime == -1 && leaseTime == -1) {
          return false;
        }
        failedLocksLimit = failedLocksLimit();
        acquiredLocks.clear();
        // reset iterator
        while (iterator.hASPrevious()) {
          iterator.previous();
        }
      } else {
        failedLocksLimit--;
      }
    }

    
    if (remainTime != -1) {
      remainTime -= System.currentTimeMillis() - time;
      time = System.currentTimeMillis();
      if (remainTime <= 0) {
        unlockInner(acquiredLocks);
        return false;
      }
    }
  }

  if (leaseTime != -1) {
    List<RFuture<Boolean>> futures = new ArrayList<>(acquiredLocks.size());
    for (RLock rLock : acquiredLocks) {
      RFuture<Boolean> future = ((RedissonLock) rLock).expireAsync(unit.toMillis(leaseTime), TimeUnit.MILLISECONDS);
      futures.add(future);
    }
   
    for (RFuture<Boolean> rFuture : futures) {
      rFuture.syncUninterruptibly();
    }
  }

  
  return true;
}

到此这篇关于Redis分布式锁之红锁的实现的文章就介绍到这了,更多相关Redis 红锁内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯