20分钟带你熟悉Redisson分布式锁设计方案

Posted 栗子~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20分钟带你熟悉Redisson分布式锁设计方案相关的知识,希望对你有一定的参考价值。

前言

  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
  而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


20分钟带你熟悉Redisson分布式锁设计方案

01 重温分布式锁

 分布式锁,也是一种锁机制,只不过是为了专门应对分布式环境而出现的,
它并不是一种全新的组件或者中间件,它只是一种机制,一种实现方式,即解决方案而已。
 它是用来保证在分布式的环境下,通过锁机制让多个客户端或者多个服务进程互斥地对"共享资源"进行访问,从而避免出现并发安全、数据不一致等问题。


01::01 分布式锁的设计的几点要求

业界普遍有几点要求:

  1. 排他性
  2. 避免死锁
  3. 高可用
  4. 可重入
  5. 公平锁(可选)

01::02 分布式锁要如何理解?

  即通过第三方带有原子性的行为来保护高并发下的安全问题。
  可能这句话对初学者有点绕口,没关系,记下来,会有帮助的。


02 Redisson分布式锁设计的优点

  Redisson分布式锁解决了采用基于redis原子性操作实现分布式锁方式的缺陷。


02::01 Redis分布式锁设计的不足

  1. 执行Redis的原子操作时、要设置EXPIRE,即Reds的key的TTL,不同的业务场景设置的过期时间是不同的,如果设置不当,很可能会影响系统与Redis服务的性能。
  2. Redis 原子操作SETNX获取分布式锁的时候没有"可重入"特性,即当一个线程获得锁时,其他线程获取锁失败,永久的失败,本质上来说是没毛病的,但有些业务场景可能要求线程具有"可重入"特性,这时候,SETNX操作就不满足于当下的需求,就得需要一些配套的逻辑进行处理,即while(true){}的代码,但这种方式即不优雅,也很有可能造成应用系统"卡顿"的风险。
  3. 当Redis原子性操作在【SETNX之后、EXPIPR之前】时,Reids服务发生宕机,同时应用服务出现问题导致该key未被删除,那么造成的影响最终会出现死锁线程,即永远没有线程可以获取到该key值的锁(未加TTL的同时锁也未被删除,导致其永久存在)。

03 Redisson分布式锁的功能特性

  1. 可重入锁
  2. 公平锁
  3. 联锁
  4. 红锁
  5. 读写锁
  6. 信号量及闭锁

04 Redisson分布式锁(可重入锁)实战

  可重入锁分为一次性和可重入,顾名词义,一次性代表着当前线程如果可以获取到分布式锁,如果成功,获取之,失败则永久失败,可重入代表着当当前线程没有获取到分布式锁的时候,它并不会立即失败,而是等待一段时间重新获取。


04::01 Redisson分布式锁(可重入锁)一次性锁实战

代码如下:

    @Autowired
    private RedissonClient redissonClient;
    /**
     * Redission 分布式锁设计(一次性锁)
     * */
    @ApiOperation(value = "Redission 分布式锁设计(一次性锁)",notes = "Redission 分布式锁设计(一次性锁)")
    @ResponseBody
    @PostMapping("/onelock")
    public ResponseBo onelock(String key)  {
        String msgValue = "onelock";
        long startTime = init(msgValue,key);
        //分布式锁名称
        final String lockName = "redissonOneLock-"+key;
        RLock lock = redissonClient.getLock(lockName);
        try{
            //尝试加锁, 上锁后10秒自动解锁
            lock.lock(10,TimeUnit.SECONDS);
            this.info("获取到一次性分布式锁");
            this.info("执行业务逻辑");
            endLog(msgValue,startTime);
            return ResponseBo.ok();
        }catch (Exception e){
            endLogError(msgValue,startTime,e);
            return ResponseBo.error("保存失败" + e.getMessage());
        }finally {
            /**
             * 注:访问共享资源结束后要释放锁
             * */
            if (lock!= null){
                this.info("释放分布式锁");
                lock.unlock();
                //注在某些严格的业务场景下,也可以调用强制释放分布式锁的方法
                //lock.forceUnlock();
            }
        }
    }

测试:
在这里插入图片描述
在这里插入图片描述


04::02 Redisson分布式锁(可重入锁)可重入锁实战

代码如下:

    @Autowired
    private RedissonClient redissonClient;
        /**
     * Redission 分布式锁设计(可重入锁)
     * */
    @ApiOperation(value = "Redission 分布式锁设计(可重入锁)",notes = "Redission 分布式锁设计(可重入锁)")
    @ResponseBody
    @PostMapping("/trylock")
    public ResponseBo trylock(String key)  {
        String msgValue = "trylock";
        long startTime = init(msgValue,key);
        //分布式锁名称
        final String lockName = "redissonTryLock-"+key;
        RLock lock = redissonClient.getLock(lockName);
        try{
           //尝试加锁, 最多等待100秒,上锁后10秒自动解锁
            Boolean aBoolean = lock.tryLock(100,10,TimeUnit.SECONDS);
            if (aBoolean){
                this.info("获取到可重入分布式锁");
                this.info("执行业务逻辑");
            }
            endLog(msgValue,startTime);
            return ResponseBo.ok();
        }catch (Exception e){
            endLogError(msgValue,startTime,e);
            return ResponseBo.error("保存失败" + e.getMessage());
        }finally {
            /**
             * 注:访问共享资源结束后要释放锁
             * */
            if (lock!= null){
                this.info("释放分布式锁");
                lock.unlock();
                //注在某些严格的业务场景下,也可以调用强制释放分布式锁的方法
                //lock.forceUnlock();
            }
        }
    }

测试:
在这里插入图片描述
在这里插入图片描述

以上是关于20分钟带你熟悉Redisson分布式锁设计方案的主要内容,如果未能解决你的问题,请参考以下文章

30分钟带您熟悉Redisson综合中间件

Redisson分布式锁设计方案

10分钟带您熟悉db乐观锁分布式锁设计方案

万字长文带你解读Redisson分布式锁的源码

20分钟带您ZooKeeper 分布式锁设计实战

又长又细,万字长文带你解读Redisson分布式锁的源码