精华内容
下载资源
问答
  • RedLock原理 RedLock是基于redis实现的分布式锁,它能够保证以下特性: 互斥性:在任何时候,只能有一个客户端能够持有锁;避免死锁: 当客户端拿到锁后,即使发生了网络分区或者客户端宕机,也不会发生死锁;...

    前言

    前面已经学习了Redission可重入锁以及公平锁的原理,接着看看Redission是如何来实现RedLock的。

    RedLock原理

    RedLock是基于redis实现的分布式锁,它能够保证以下特性:

    • 互斥性:在任何时候,只能有一个客户端能够持有锁;避免死锁:
    • 当客户端拿到锁后,即使发生了网络分区或者客户端宕机,也不会发生死锁;(利用key的存活时间)
    • 容错性:只要多数节点的redis实例正常运行,就能够对外提供服务,加锁或者释放锁;

    RedLock算法思想,意思是不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁,n / 2 + 1,必须在大多数redis节点上都成功创建锁,才能算这个整体的RedLock加锁成功,避免说仅仅在一个redis实例上加锁而带来的问题。

    这里附上一个前几天对RedLock解析比较透彻的文章:
    https://mp.weixin.qq.com/s/gOYWLg3xYt4OhS46woN_Lg

    Redisson实现原理

    Redisson中有一个MultiLock的概念,可以将多个锁合并为一个大锁,对一个大锁进行统一的申请加锁以及释放锁

    而Redisson中实现RedLock就是基于MultiLock 去做的,接下来就具体看看对应的实现吧

    RedLock使用案例

    先看下官方的代码使用:
    (https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers#84-redlock)

    RLock lock1 = redisson1.getLock("lock1");
    RLock lock2 = redisson2.getLock("lock2");
    RLock lock3 = redisson3.getLock("lock3");
    
    RLock redLock = anyRedisson.getRedLock(lock1, lock2, lock3);
    
    // traditional lock method
    redLock.lock();
    
    // or acquire lock and automatically unlock it after 10 seconds
    redLock.lock(10, TimeUnit.SECONDS);
    
    // or wait for lock aquisition up to 100 seconds 
    // and automatically unlock it after 10 seconds
    boolean res = redLock.tryLock(100, 10, TimeUnit.SECONDS);
    if (res) {
       try {
         ...
       } finally {
           redLock.unlock();
       }
    }

    这里是分别对3个redis实例加锁,然后获取一个最后的加锁结果。

    RedissonRedLock实现原理

    上面示例中使用redLock.lock()或者tryLock()最终都是执行RedissonRedLock中方法。

    RedissonRedLock 继承自RedissonMultiLock, 实现了其中的一些方法:

    public class RedissonRedLock extends RedissonMultiLock {
        public RedissonRedLock(RLock... locks) {
            super(locks);
        }
    
        /**
         * 锁可以失败的次数,锁的数量-锁成功客户端最小的数量
         */
        @Override
        protected int failedLocksLimit() {
            return locks.size() - minLocksAmount(locks);
        }
        
        /**
         * 锁的数量 / 2 + 1,例如有3个客户端加锁,那么最少需要2个客户端加锁成功
         */
        protected int minLocksAmount(final List<RLock> locks) {
            return locks.size()/2 + 1;
        }
    
        /** 
         * 计算多个客户端一起加锁的超时时间,每个客户端的等待时间
         * remainTime默认为4.5s
         */
        @Override
        protected long calcLockWaitTime(long remainTime) {
            return Math.max(remainTime / locks.size(), 1);
        }
        
        @Override
        public void unlock() {
            unlockInner(locks);
        }
    
    }

    看到locks.size()/2 + 1 ,例如我们有3个客户端实例,那么最少2个实例加锁成功才算分布式锁加锁成功。

    接着我们看下lock()的具体实现

    RedissonMultiLock实现原理

    ```java
    public class RedissonMultiLock implements Lock {
    
        final List<RLock> locks = new ArrayList<RLock>();
    
        public RedissonMultiLock(RLock... locks) {
            if (locks.length == 0) {
                throw new IllegalArgumentException("Lock objects are not defined");
            }
            this.locks.addAll(Arrays.asList(locks));
        }
    
        public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
            long newLeaseTime = -1;
            if (leaseTime != -1) {
                // 如果等待时间设置了,那么将等待时间 * 2
                newLeaseTime = unit.toMillis(waitTime)*2;
            }
            
            // time为当前时间戳
            long time = System.currentTimeMillis();
            long remainTime = -1;
            if (waitTime != -1) {
                remainTime = unit.toMillis(waitTime);
            }
            // 计算锁的等待时间,RedLock中:如果remainTime=-1,那么lockWaitTime为1
            long lockWaitTime = calcLockWaitTime(remainTime);
            
            // RedLock中failedLocksLimit即为n/2 + 1
            int failedLocksLimit = failedLocksLimit();
            List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size());
            // 循环每个redis客户端,去获取锁
            for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {
                RLock lock = iterator.next();
                boolean lockAcquired;
                try {
                    // 调用tryLock方法去获取锁,如果获取锁成功,则lockAcquired=true
                    if (waitTime == -1 && leaseTime == -1) {
                        lockAcquired = lock.tryLock();
                    } else {
                        long awaitTime = Math.min(lockWaitTime, remainTime);
                        lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);
                    }
                } catch (Exception e) {
                    lockAcquired = false;
                }
                
                // 如果获取锁成功,将锁加入到list集合中
                if (lockAcquired) {
                    acquiredLocks.add(lock);
                } else {
                    // 如果获取锁失败,判断失败次数是否等于失败的限制次数
                    // 比如,3个redis客户端,最多只能失败1次
                    // 这里locks.size = 3, 3-x=1,说明只要成功了2次就可以直接break掉循环
                    if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {
                        break;
                    }
    
                    // 如果最大失败次数等于0
                    if (failedLocksLimit == 0) {
                        // 释放所有的锁,RedLock加锁失败
                        unlockInner(acquiredLocks);
                        if (waitTime == -1 && leaseTime == -1) {
                            return false;
                        }
                        failedLocksLimit = failedLocksLimit();
                        acquiredLocks.clear();
                        // 重置迭代器 重试再次获取锁
                        while (iterator.hasPrevious()) {
                            iterator.previous();
                        }
                    } else {
                        // 失败的限制次数减一
                        // 比如3个redis实例,最大的限制次数是1,如果遍历第一个redis实例,失败了,那么failedLocksLimit会减成0
                        // 如果failedLocksLimit就会走上面的if逻辑,释放所有的锁,然后返回false
                        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<RFuture<Boolean>>(acquiredLocks.size());
                for (RLock rLock : acquiredLocks) {
                    RFuture<Boolean> future = rLock.expireAsync(unit.toMillis(leaseTime), TimeUnit.MILLISECONDS);
                    futures.add(future);
                }
                
                for (RFuture<Boolean> rFuture : futures) {
                    rFuture.syncUninterruptibly();
                }
            }
            
            return true;
        }
    }

     

     

    核心代码都已经加了注释,实现原理其实很简单,基于RedLock思想,遍历所有的Redis客户端,然后依次加锁,最后统计成功的次数来判断是否加锁成功。

    申明

    本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫,如若转载请标明来源!

    感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫

    22.jpg

    展开全文
  • Redlock原理分析

    2019-07-16 14:10:37
      Redlock全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁。使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击);官网文档地址如下:...

    转载自:https://blog.csdn.net/b644ROfP20z37485O35M/article/details/89369482
        http://ifeve.com/慢谈-redis-实现分布式锁-以及-redisson-源码解析/

      
      Redlock全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁。使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击);官网文档地址如下:https://redis.io/topics/distlock
      这个锁的算法实现了多redis实例的情况,相对于单redis节点来说,优点在于 防止单节点故障造成整个服务停止运行的情况;并且在多节点中锁的设计,及多节点同时崩溃等各种意外情况有独特的设计方法;

      最低保证分布式锁的有效性及安全性的要求如下:
      1.互斥;任何时刻只能有一个client获取锁
      2.释放死锁;即使锁定资源的服务崩溃或者分区,仍然能释放锁
      3.容错性;只要多数redis节点(一半以上)在使用,client就可以获取和释放锁

      注意,基于故障转移实现的redis主从无法真正实现Redlock:因为redis在进行主从复制时是异步完成的,比如在clientA获取锁后,主redis复制数据到从redis过程中崩溃了,导致没有复制到从redis中,然后从redis选举出一个升级为主redis,造成新的主redis没有clientA 设置的锁,这是clientB尝试获取锁,并且能够成功获取锁,导致互斥失效;

      
    redis单实例中实现分布式锁的正确方式(原子性非常重要)
      1.设置锁时,使用set命令,因为其包含了setnx,expire的功能,起到了原子操作的效果,给key设置随机值,并且只有在key不存在时才设置成功返回True,并且设置key的过期时间(最好用毫秒);

    SET key_name my_random_value NX PX 30000                  
    # NX 表示if not exist 就设置并返回True,否则不设置并返回False   
    # PX 表示过期时间用毫秒级
    # 30000 表示这些毫秒时间后此key过期
    

      2.在获取锁后,并完成相关业务后,需要删除自己设置的锁(必须是只能删除自己设置的锁,不能删除他人设置的锁);
      删除原因:保证服务器资源的高利用效率,不用等到锁自动过期才删除;
      删除方法:最好使用Lua脚本删除(redis保证执行此脚本时不执行其他操作,保证操作的原子性);
      代码如下;逻辑是 先获取key,如果存在并且值是自己设置的就删除此key;否则就跳过;

    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end
    

      
    多节点redis实现的分布式锁算法(RedLock):有效防止单点故障
      假设有5个完全独立的redis主服务器
      1.获取当前时间戳
      2.client尝试按照顺序使用相同的key,value获取所有redis服务的锁,在获取锁的过程中的获取时间比锁过期时间短很多,这是为了不要过长时间等待已经关闭的redis服务。并且试着获取下一个redis实例。比如:TTL为5s,设置获取锁最多用1s,所以如果一秒内无法获取锁,就放弃获取这个锁,从而尝试获取下个锁
      3.client通过获取所有能获取的锁后的时间减去第一步的时间,这个时间差要小于TTL时间并且至少有3个redis实例成功获取锁,才算真正的获取锁成功
      4.如果成功获取锁,则锁的真正有效时间是 TTL减去第三步的时间差 的时间;比如:TTL 是5s,获取所有锁用了2s,则真正锁有效时间为3s(其实应该再减去时钟漂移);
      5.如果客户端由于某些原因获取锁失败,便会开始解锁所有redis实例;因为可能已经获取了小于3个锁,必须释放,否则影响其他client获取锁

      
    RedLock注意点(Safety arguments)
      1.先假设client获取所有实例,所有实例包含相同的key和过期时间(TTL) ,但每个实例set命令时间不同导致不能同时过期,第一个set命令之前是T1,最后一个set命令后为T2,则此client有效获取锁的最小时间为TTL-(T2-T1)-时钟漂移;
      2.对于以N/2+ 1(也就是一半以 上)的方式判断获取锁成功,是因为如果小于一半判断为成功的话,有可能出现多个client都成功获取锁的情况,从而使锁失效
      3.一个client锁定大多数事例耗费的时间大于或接近锁的过期时间,就认为锁无效,并且解锁这个redis实例(不执行业务);只要在TTL时间内成功获取一半以上的锁便是有效锁;否则无效

    系统有活性的三个特征
      1.能够自动释放锁
      2.在获取锁失败(不到一半以上),或任务完成后 能够自动释放锁,不用等到其自动过期
      3.在client重试获取哦锁前(第一次失败到第二次重试时间间隔)大于第一次获取锁消耗的时间;
      4.重试获取锁要有一定次数限制

      
    RedLock性能及崩溃恢复的相关解决方法
      1.如果redis没有持久化功能,在clientA获取锁成功后,所有redis重启,clientB能够再次获取到锁,这样违法了锁的排他互斥性;

      2.如果启动AOF永久化存储,事情会好些。
      举例:当我们重启redis后,由于redis过期机制是按照unix时间戳走的,所以在重启后,然后会按照规定的时间过期,不影响业务;但是由于AOF同步到磁盘的方式默认是每秒-次,如果在一秒内断电,会导致数据丢失,立即重启会造成锁互斥性失效;但如果同步磁盘方式使用Always(每一个写命令都同步到硬盘)造成性能急剧下降;所以在锁完全有效性和性能方面要有所取舍;

      3.有效解决既保证锁完全有效性及性能高效及即使断电情况的方法是 redis同步到磁盘方式保持默认的每秒,在redis无论因为什么原因停掉后要等待TTL时间后再重启;缺点是 在TTL时间内服务相当于暂停状态;

      
    总结:
      1.TTL时长 要大于正常业务执行的时间+获取所有redis服务消耗时间+时钟漂移
      2.获取redis所有服务消耗时间要 远小于TTL时间,并且获取成功的锁个数要 在总数的一般以上:N/2+1
      3.尝试获取每个redis实例锁时的时间要 远小于TTL时间
      4.尝试获取所有锁失败后 重新尝试一定要有一定次数限制
      5.在redis崩溃后(无论一个还是所有),要延迟TTL时间重启redis
      6.在实现多redis节点时要结合单节点分布式锁算法 共同实现


    通过 Redisson 实现分布式可重入锁,RedissonLock是可重入的,并且考虑了失败重试,可以设置锁的最大等待时间, 在实现上也做了一些优化,减少了无效的锁申请,提升了资源的利用率。需要注意的是,RedissonLock 同样没有解决 节点挂掉的时候,存在丢失锁的风险的问题。而现实情况是有一些场景无法容忍的,所以 Redisson 提供了实现了redlock算法的 RedissonRedLock,RedissonRedLock 真正解决了单点失败的问题,代价是需要额外的为 RedissonRedLock 搭建Redis环境。所以,如果业务场景可以容忍这种小概率的错误,则推荐使用 RedissonLock, 如果无法容忍,则推荐使用 RedissonRedLock。

    RedissonLock加锁流程:

    解锁流程:

    展开全文
  • 由此 redis官方推荐 redlock 来解决这个问题 使用场景 多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) 优点 防止了 单节点故障造成整个服务停止运行的情况; 在多节点中锁...

    前言

    上篇文章介绍了通过
    
    SET key_name my_random_value NX PX 30000                  
    NX 表示if not exist 就设置并返回True,否则不设置并返回False   
    PX 表示过期时间用毫秒级, 30000 表示这些毫秒时间后此key过期
    
    方式实现的redis分布锁
    
    但有缺点:
    
    只作用在一个Redis节点上,即使Redis通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况:
    
    在Redis的master节点上拿到了锁;
    
    但是这个加锁的key还没有同步到slave节点;
    
    master故障,发生故障转移,slave节点升级为master节点;
    
    导致锁丢失。
    
    由此 redis官方推荐 redlock 来解决这个问题
    

    使用场景

    多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击)
    

    优点

    • 防止了 单节点故障造成整个服务停止运行的情况;

    • 在多节点中锁的设计,及多节点同时崩溃等各种意外情况有自己独特的设计方法

    概念说明

    • 1.TTL:Time To Live;只 redis key 的过期时间或有效生存时间

    • 2.clock drift:时钟漂移;指两个电脑间时间流速基本相同的情况下,两个电脑(或两个进程间)时间的差值;如果电脑距离过远会造成时钟漂移值 过大

    最低保证分布式锁的有效性及安全性的要求

    • 1.互斥;任何时刻只能有一个client获取锁

    • 2.释放死锁;即使锁定资源的服务崩溃或者分区,仍然能释放锁

    • 3.容错性;只要多数redis节点(一半以上)在使用,client就可以获取和释放锁

    使用redession实现分布锁的过程

    假设有5个完全独立的redis主服务器
    
    • 1.获取当前时间戳

    • 2.client尝试按照顺序使用相同的key,value获取所有redis服务的锁,在获取锁的过程中的获取时间比锁过期时间短很多,这是为了不要过长时间等待已经关闭的redis服务。并且试着获取下一个redis实例。

      比如:TTL为5s,设置获取锁最多用1s,所以如果一秒内无法获取锁,就放弃获取这个锁,从而尝试获取下个锁

    • 3.client通过获取所有能获取的锁后的时间减去第一步的时间,这个时间差要小于TTL时间并且至少有3个redis实例成功获取锁,才算真正的获取锁成功

    • 4.如果成功获取锁,则锁的真正有效时间是 TTL减去第三步的时间差 的时间;比如:TTL 是5s,获取所有锁用了2s,则真正锁有效时间为3s(其实应该再减去时钟漂移);

    • 5.如果客户端由于某些原因获取锁失败,便会开始解锁所有redis实例;因为可能已经获取了小于3个锁,必须释放,否则影响其他client获取锁

    代码实现

    maven依赖

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

    获取redession客户端连接

    业务处理接口

    具体的业务逻辑实现都需要实现该接口
    

    封装锁管理接口

    锁管理接口实现类

    调用加锁

    redessoin获取锁和释放锁源码分析

    获取锁

    跟踪RLock类的lock.tryLock(100, lockTime, TimeUnit.SECONDS);方法
    
    可以找到方法
    

    现在来分析下其中的lua脚本
    
    if (redis.call('exists', KEYS[1]) == 0) 
    
    首先分布式锁的KEY不能存在,,
    
    then redis.call('hset', KEYS[1], ARGV[2], 1); 
    
    如果确实不存在,那么执行hset命令(hset REDLOCK_KEY uuid+threadId 1)
    
    redis.call('pexpire', KEYS[1], ARGV[1]); 
    
    并通过pexpire设置失效时间(也是锁的租约时间)
    
    if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) 
    
    如果分布式锁的KEY已经存在,并且value也匹配,表示是当前线程持有的锁,
    
    then redis.call('hincrby', KEYS[1], ARGV[2], 1); 
    redis.call('pexpire', KEYS[1], ARGV[1]); 
    
    那么重入次数加1,并且设置失效时间
    
    return redis.call('pttl', KEYS[1])
    
    获取分布式锁的KEY的失效时间毫秒数
    

    释放锁

    if (redis.call('exists', KEYS[1]) == 0)
    then redis.call('publish', KEYS[2], ARGV[1])
    
    如果分布式锁KEY不存在,那么向channel发布一条消息
    
    if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) 
    then return nil
    
    如果分布式锁存在,但是value不匹配,表示锁已经被占用,那么直接返回
    
    local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
    
    如果就是当前线程占有分布式锁,那么将重入次数减1
    
    if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]); 
    
    重入次数减1后的值如果大于0,表示分布式锁有重入过,那么只设置失效时间,还不能删除
    
    return 0; else redis.call('del', KEYS[1]); 
    redis.call('publish', KEYS[2], ARGV[1]); 
    
    重入次数减1后的值如果为0,表示分布式锁只获取过1次,那么删除这个KEY,并发布解锁消息
    

    DEMO源码

    https://gitee.com/pingfanrenbiji/redis-demo
    

    参考文章

    https://www.cnblogs.com/rgcLOVEyaya/p/RGC_LOVE_YAYA_1003days.html
    https://yq.aliyun.com/articles/674394
    

    本文使用 mdnice 排版

    展开全文
  • RedLock分布式锁原理

    2021-02-09 16:05:18
    Redlock分布式锁 传统的Redis分布式锁缺陷 使用传统的Redis分布式锁: SET key_name my_random_value NX PX 30000 NX 表示if not exist 就设置并返回True,否则不设置并返回False PX 表示过期时间用毫秒级, 30000 ...

    Redlock分布式锁

    传统的Redis分布式锁缺陷

    使用传统的Redis分布式锁:
    SET key_name my_random_value NX PX 30000
    NX 表示if not exist 就设置并返回True,否则不设置并返回False
    PX 表示过期时间用毫秒级, 30000 表示这些毫秒时间后此key过期
    传统的Redis分布式锁有缺点:
    只作用在一个Redis节点上,即使Redis通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况.
    比如说在Redis的master节点上拿到了锁,但是这个加锁的key还没有同步到slave节点,master故障,发生故障转移,slave节点升级为master节点.但是这个新的Master并没有锁信息,此时就导致锁丢失.
    就会出现严重的问题.因为锁丢失了,此时新的线程来尝试获取锁,就能获取到了.这样的话程序就有了严重的bug.
    由此 redis官方推荐 redlock 来解决这个问题

    RedLock原理简述

    假设有5个redis节点,这些节点之间既没有主从,也没有集群关系。客户端用相同的key和随机值在5个节点上请求锁,请求锁的超时时间应小于锁自动释放时间。当在3个(超过半数)redis上请求到锁的时候,才算是真正获取到了锁。如果没有获取到锁,则把部分已锁的redis释放掉。

    RedLock详细解答

    什么是 RedLock

    Redis 官方站这篇文章提出了一种权威的基于 Redis 实现分布式锁的方式名叫 Redlock,此种方式比原先的单节点的方法更安全。它可以保证以下特性:

    1. 安全特性:互斥访问,即永远只有一个 client 能拿到锁
    2. 避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区
    3. 容错性:只要大部分 Redis 节点存活就可以正常提供服务

    怎么在单节点上实现分布式锁

    SET resource_name my_random_value NX PX 30000

    主要依靠上述命令,该命令仅当 Key 不存在时(NX保证)set 值,并且设置过期时间 3000ms (PX保证),值 my_random_value 必须是所有 client 和所有锁请求发生期间唯一的,释放锁的逻辑是:

    if redis.call("get",KEYS[1]) == ARGV[1] then
        return redis.call("del",KEYS[1])
    else
        return 0
    end
    

    上述实现可以避免释放另一个client创建的锁,如果只有 del 命令的话,那么如果 client1 拿到 lock1 之后因为某些操作阻塞了很长时间,此时 Redis 端 lock1 已经过期了并且已经被重新分配给了 client2,那么 client1 此时再去释放这把锁就会造成 client2 原本获取到的锁被 client1 无故释放了,但现在为每个 client 分配一个 unique 的 string 值可以避免这个问题。至于如何去生成这个 unique string,方法很多随意选择一种就行了。

    Redlock 算法

    算法很易懂,起 5 个 master 节点,分布在不同的机房尽量保证可用性。为了获得锁,client 会进行如下操作:

    1. 得到当前的时间,微妙单位
    2. 尝试顺序地在 5 个实例上申请锁,当然需要使用相同的 key 和 random value,这里一个 client 需要合理设置与 master 节点沟通的 timeout 大小,避免长时间和一个 fail 了的节点浪费时间
    3. 当 client 在大于等于 3 个 master 上成功申请到锁的时候,且它会计算申请锁消耗了多少时间,这部分消耗的时间采用获得锁的当下时间减去第一步获得的时间戳得到,如果锁的持续时长(lock validity time)比流逝的时间多的话,那么锁就真正获取到了。
    4. 如果锁申请到了,那么锁真正的 lock validity time 应该是 origin(lock validity time) - 申请锁期间流逝的时间
    5. 如果 client 申请锁失败了,那么它就会在少部分申请成功锁的 master 节点上执行释放锁的操作,重置状态

    失败重试

    如果一个 client 申请锁失败了,那么它需要稍等一会在重试避免多个 client 同时申请锁的情况,最好的情况是一个 client 需要几乎同时向 5 个 master 发起锁申请。另外就是如果 client 申请锁失败了它需要尽快在它曾经申请到锁的 master 上执行 unlock 操作,便于其他 client 获得这把锁,避免这些锁过期造成的时间浪费,当然如果这时候网络分区使得 client 无法联系上这些 master,那么这种浪费就是不得不付出的代价了。

    放锁

    放锁操作很简单,就是依次释放所有节点上的锁就行了

    性能、崩溃恢复和 fsync

    如果我们的节点没有持久化机制,client 从 5 个 master 中的 3 个处获得了锁,然后其中一个重启了,这是注意 整个环境中又出现了 3 个 master 可供另一个 client 申请同一把锁! 违反了互斥性。如果我们开启了 AOF 持久化那么情况会稍微好转一些,因为 Redis 的过期机制是语义层面实现的,所以在 server 挂了的时候时间依旧在流逝,重启之后锁状态不会受到污染。但是考虑断电之后呢,AOF部分命令没来得及刷回磁盘直接丢失了,除非我们配置刷回策略为 fsnyc = always,但这会损伤性能。解决这个问题的方法是,当一个节点重启之后,我们规定在 max TTL 期间它是不可用的,这样它就不会干扰原本已经申请到的锁,等到它 crash 前的那部分锁都过期了,环境不存在历史锁了,那么再把这个节点加进来正常工作。

    展开全文
  • 笔者现将RedLock核心理论其翻译如下: 在分布式版本的算法里我们假设我们有N个Redis master节点,这些节点都是完全独立的,我们不用任何复制或者其他隐含的分布式协调算法。我们已经描述了如何在单节点环境下安全地...
  • Redlock是一种算法,Redlock也就是Redis Distributed Lock,可用实现多节点redis的分布式锁。 RedLock官方推荐,Redisson完成了对Redlock算法封装。 此种方式具有以下特性: ... RedLock原理(了解).
  • 笔者现将RedLock核心理论其翻译如下: 在分布式版本的算法里我们假设我们有N个Redis master节点,这些节点都是完全独立的,我们不用任何复制或者其他隐含的分布式协调算法。我们已经描述了如何在单节点环境下安全地...
  • 文章目录引入:Redis SetNX局限性RedLock原理解决宕机恢复后锁的问题单机锁和多机锁的比较为什么RedLock是不可靠的! 引入:Redis SetNX局限性 我在Java架构直通车——基于Redis的Set NX实现分布式锁一文中写了,...
  • 上一文分布式锁系列–03关于分布式锁的选型分析01中,我们看到了单节点的redis分布式锁在failover时产生了无法解决的安全问题,因此,Redis的作者...Redlock获取锁的原理如下: 1.获取当前时间(毫秒数): t1。 2....
  • Redlock(redis分布式锁)原理分析 原文:Redlock(redis分布式锁)原理分析Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁; 使用场景:多个服务间保证同一时刻同一时间段内...
  • RedLock 原理理一下: (1)获取当前时间戳,单位是毫秒 (2)和RedissonMultiLock一样,一次轮询尝试去每个机器上创建锁,需要加一个超时时间,如果超过一定时间就表示获取锁失败 (3)尝试在大多数节点上建立一...
  • 使用前建议先了解一下Redlock算法的原理, 使用 try { $ lock = $ this -> container -> get ( RedLock ::class)-> setRedisPoolName ()-> setRetryCount ( 1 )-> lock ( 'redlock-hyperf-test' , 60000 ); //do ...
  • 一、RedLock简介 全名叫做 Redis Distributed Lock,即使用redis实现的分布式锁 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击)。 官网文档地址如下:...
  • 转载 Redlock(redis分布式锁)原理分析 Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁; 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发...

空空如也

空空如也

1 2 3 4 5 6
收藏数 115
精华内容 46
关键字:

redlock原理