分布式红锁的加锁失败的设计原理

1.先把3台 redis key全部清空(为了不受debug干扰,必须先删除锁)
127.0.0.1:6379> flushdb
OK

都设置为30分钟超时 过期
2.isLock = redLock.tryLock(10006030, 10006030, TimeUnit.MILLISECONDS);

试验步骤:

  1. 先启动3台redis实例,然后启动springboot
  2. springboot启动成功后,停2台redis实例。(不能先停2台redis,不然springboot起不来)

步骤1:springboot启动成功后,停2台redis实例。

[root@node2 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
1e6e3900e68c        redis:5.0.7         "docker-entrypoint.s…"   6 days ago          Up 4 minutes        0.0.0.0:6383->6379/tcp   redis-master-3
1b9030d50927        redis:5.0.7         "docker-entrypoint.s…"   6 days ago          Up 4 minutes        0.0.0.0:6382->6379/tcp   redis-master-2
c86403dcb3d8        redis:5.0.7         "docker-entrypoint.s…"   6 days ago          Up 8 hours          0.0.0.0:6381->6379/tcp   redis-master-1
[root@node2 ~]#
[root@node2 ~]#
[root@node2 ~]# docker stop redis-master-3 redis-master-2
redis-master-3
redis-master-2
    @Overridepublic boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
//        try {
//            return tryLockAsync(waitTime, leaseTime, unit).get();
//        } catch (ExecutionException e) {
//            throw new IllegalStateException(e);
//        }long newLeaseTime = -1;if (leaseTime != -1) {if (waitTime == -1) {newLeaseTime = unit.toMillis(leaseTime);} else {newLeaseTime = unit.toMillis(waitTime)*2;}}long time = System.currentTimeMillis();long remainTime = -1;if (waitTime != -1) {remainTime = unit.toMillis(waitTime);}long lockWaitTime = calcLockWaitTime(remainTime);//步骤2:计算可以容忍接受加锁失败节点个数限制(N-(N/2+1))=(3-(3/2+1))=1int failedLocksLimit = failedLocksLimit(); ==1List<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;}//步骤3:拿锁成功后,统计成功的redis实例数if (lockAcquired) {acquiredLocks.add(lock);} else {//步骤4:拿锁失败的话,那就复杂了计算可以容忍接受加锁失败节点数,是否达到?(N-(N/2+1))=(3-(3/2+1))=1如果已经达到,就认定最终申请锁失败,则没有必要继续从后面的节点申请了因为红锁算法要求至少N/2+1=3/2+1=2个节点都加锁成功了,才算最终的锁申请成功。//刚好N/2+1=3/2+1=2是成功的,例如 3个或2个都是成功,就退出,代表获取锁成功。if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {break;}//步骤B:例如redis3个节点,第一个成功,第二失败,第三失败,,就直接进入failedLocksLimit=0if (failedLocksLimit == 0) {//解锁第一个成功的unlockInner(acquiredLocks);//等待时间已经消化完就,就直接返回false,获取锁失败。if (waitTime == -1) {return false;}//计算可以容忍接受加锁失败节点个数限制(N-(N/2+1))=(3-(3/2+1))=1failedLocksLimit = failedLocksLimit();//清除成功的list,例如redis3个节点,第一个成功,第二失败,第三失败,就是吧第一个清除,然后重新来。acquiredLocks.clear();//把iterator的坐标重新初始化,然后重新进入新的循环// reset iteratorwhile (iterator.hasPrevious()) {iterator.previous();}//总结:failedLocksLimit == 0的设计原理,就是让for循环一直循环下去,除非出现2种情况才退出死循环1.waitTime 或 remainTime消化完,退出循环2.redis实例恢复正常  (例如启动  docker start redis-master-3 redis-master-2)就正常拿到锁了} else {//步骤A:加锁失败节点个数限制-1,然后继续循环,例如redis3个节点,第一个成功,第二失败,限制failedLocksLimit=0failedLocksLimit--;}}//步骤5: 只有等到remainTime消化完,退出死循环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;}

基于以上代码,我们分为5个步骤分析,得出一个结论:
1.整个算法过程中都是围绕N/2+1=3/2+1=2的成功个数来设计的,如果拿不到N/2+1=3/2+1=2,算法会一直死循环下去,,除非出现2种情况才退出死循环
1.waitTime 或 remainTime消化完,退出循环
2.redis实例恢复正常 (例如启动 docker start redis-master-3 redis-master-2)就正常拿到锁了
2.这种设计,要特别小心waitTime,这个waitTime一定要设置短,不然redis宕机的情况下,会出现死循环,整个系统卡死。

分布式红锁的加锁失败的设计原理相关推荐

  1. 分布式红锁的加锁的lua底层设计原理

    分布式红锁的加锁的lua底层设计原理 提前做2个动作: 1.先把3台 redis key全部清空(为了不受debug干扰,必须先删除锁) 127.0.0.1:6379> flushdb OK 2 ...

  2. 分布式红锁的waitTime的设计原理

    分布式红锁的waitTime的设计原理 提前做2个动作: 1.先把3台 redis key全部清空 127.0.0.1:6379> flushdb OK 2.isLock = redLock.t ...

  3. 分布式红锁的leaseTime的设计原理

    3.分布式红锁的leaseTime的设计原理 提前做2个动作: 1.先把3台 redis key全部清空(为了不受debug干扰,必须先删除锁) 127.0.0.1:6379> flushdb ...

  4. 采用docker部署3台Redis分布式红锁实例

    采用docker部署3台Redis分布式红锁实例 docker run -p 6381:6379 --name redis-master-1 -d redis:5.0.7 docker run -p ...

  5. java中的saturn_Saturn分布式调度平台系列:高屋建瓴之设计原理简析

    由于业务系统中使用了Saturn作为分布式调度平台并且计划对其作二次开发,因此看了官方文档及源码,简单做了梳理与总结.Saturn是唯品会开源的一款定时任务调度平台,相对于传统的Spring Batc ...

  6. 购买steam余额有风险吗?以及N种被红锁的情况

    购买steam余额有风险吗?以及N种被红锁的情况 无论是游戏玩家,还是像我们这类靠倒卖装备赚钱的小商贩,都面临充值美金余额的问题,我们现在主要是找的专业充值渠道做代充. 最近我发现群里有极个别学员通过 ...

  7. steam多种被红锁的情况,购买余额有风险吗?

    无论是游戏玩家,还是像我们这类靠倒卖装备赚钱的小商贩,都面临充值美金余额的问题,我们现在主要是找的专业充值渠道做代充. 最近我发现群里有极个别学员通过自己的方法找到了一些买余额的渠道.听说还被红锁过. ...

  8. 当steam遇到红锁怎么办?

    什么是买余额呢? 指的就是卖家通过steam市场里面的饰品出售功能,把steam账号里的余额转移到买家账号中. 大家都知道,自从充值卡锁区以后,获取折扣steam余额的方式无外乎三种: Steam市场 ...

  9. Redis核心数据结构List应用场景-商品列表、缓存击穿、PV阅读量、抢红包、推送帖子、普通分布式锁、Redis可重入锁与红锁

    List应用场景 Redis之List 一. Redis list命令实战 二.商品列表 高并发的淘宝聚划算实现技术方案 SpringBoot+Redis实现商品列表功能 二.缓存击穿 什么是缓存击穿 ...

最新文章

  1. Pytorch的torch.cat实例
  2. Delphi中点击网页弹出的Alert对话框的确定按钮
  3. linux下调试thread 类_在 RISC-V 芯片 GD32V 上运行 RT-Thread
  4. redhat linux ls ls,Linux(3)RedHat7 基本命令二-ls命令詳解
  5. 框架选修课之dom4j解析xml字符串实例
  6. Eclipse字符集设置方式
  7. spring mvc传值html页面,spring mvc向前台页面传值-ModelAndView
  8. python ssh
  9. Abstract 的使用
  10. python php 网站_python php网站
  11. python与线性代数 矩阵
  12. 用RDA方式同步SQLCE与SQL SERVER数据库
  13. java培训韩顺平_java韩顺平视频教程
  14. Python tkinter Canvas画布完全攻略
  15. python 基于金字塔的图像融合
  16. postgresql注入笔记
  17. [Java] 身份证号码验证
  18. 手游服务器微信互通,9月14日部分服务器数据互通公告
  19. 数字和ASII码之间的转换
  20. 四巫日来临本周硅铁、铁矿石领跌,铁矿石认沽最高31倍,钢厂利润回升2022.6.17

热门文章

  1. SQL Server 实现递归获取层级数据
  2. 系统集成管理师2011下半年软考透解 四
  3. 在centos 6.5下安装svn (Subversion)
  4. 企业运维之域控篇(三)--加入域
  5. Router Configuration5
  6. 14.jQuery常用方法
  7. 微信小程序 canvas 绘图问题
  8. ssh(安全协议外壳)
  9. Codeforces Round #879 (Div. 2) C. Short Program
  10. 我的Android第一章