首页 > 数据库 >Redisson看门狗机制你了解多少

Redisson看门狗机制你了解多少

时间:2024-12-24 15:56:13浏览次数:5  
标签:加锁 Redis 看门狗 Redisson 线程 key 机制 续期

前言

谈到Redisson就不得不说Redis了,一想到Redis就不得不想到并发编程锁机制,一想到锁机制那么就不能不考虑一个很头疼的问题,如何保证原子性的问题,高QPS请求量的系统对每次执行数据的原子性由为的关键,保证不了原子性就会导致一系列重复提交的操作,重复的数据导致在某些逻辑运算的时候发生误差;

ACID的特性首先是原子性,原子性永远是放在首位的,所以我们首先要解决的就是接口请求的原子性;

Redis分布式锁的原子性

Redis分布式锁到底能不能保证原子性,这是面试会被经常问到的一个问题。大部分的人回答都是不能保证原子性,但是其中的所以然大家都很模糊,我也一样,但为什么还在用Redis的分布式锁,如何让它可以具有原子性呢?

Redis分布式锁实现

SET NX相信大家都知道是redis实现加锁的一个命令,这里用Jedis封装的Api接口去对redis进行使用,Jedis是Redis官方推荐的面向Java操作Redis的客户段,RedisTemplate是SpringDataRedis中对Redis的封装客户端,方便的就是可以搭配Spring框架使用,如Spring cache

先上代码吧,这是我曾经写的一段关于redis分布式锁的代码,主要用于重复提交的判断,这里我用了jedis的setnx方法,加锁后的返回不为null && 值等于1的时候表示加锁成功,并且调用expire方法对key进行赋过期时间,业务处理完成后进行锁的释放,防止死锁,这里是常规的redis的加锁方式;



/**
 * 分布式事务锁-判断是否请求过
 * 
 * @param key 键
 * @param time 过期时间
 * @return true:存在
 */
@HystrixCommand(fallbackMethod = "isExistFail")
public boolean isExist(String key, int time) {
    Jedis jedis = null;
    try {
        jedis = jedisPoolManager.getJedis();
        String uniqKey = JEDIS_KEYNAME + key;
        String val = jedis.get(uniqKey);
        if (val != null) {
            return true;
        }

        if (lock.tryLock(1, TimeUnit.SECONDS)) {
            try {
                    Long flag = jedis.setnx(uniqKey, LOCAL_VAL);
                if (flag != null && flag.intValue() == 1) {
                    jedis.expire(uniqKey, time);
                } else {
                    throw new ExceptionTyche("加锁失败! ");
                }
            } finally {
                lock.unlock();
            }
        } else {
            log.info("执行Redis超时!直接返回!");
        }
    } catch (Exception e) {
        log.warn("Redis缓存异常! key={} errMsg:" + e.getMessage(), key, e);
    } finally {
        jedisPoolManager.close(jedis); // !!!关闭
    }
    return false;
}

细心的小伙伴可以看到, 我在setnx加锁之前,用了lock.tryLock这个方法,用jdk的锁先尝试进行获取锁,如果没有获取到直接返回,这样就能在一定程度上避免通过redis加锁后,业务逻辑还未执行完锁超时进行释放,导致下次同样的key获取到锁就会出现重复提交的操作

并且使用了HystrixCommand熔断注解,防止在高并发的情况下加锁方法出现异常,对其进行降级,保证业务提交的原子性;

Redisson分布式锁的原子性

关于Redisson是目前使用比较多的一个关于分布式锁的客户端,其主要原理相信大家知道,那就是watchDog机制,俗称“看门狗机制”,由于这种机制能对锁的过期时间进行续期在很大程度上能保证加锁的原子性;

Redisson看门狗机制

前段时间突然遇到了这么一个问题,Redisson锁是统一进行续期的还是分开续期的,之前确实没有考虑过,下面来看下源码具体分析下;

这里我使用的是,redisson3.8.2的版本


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

这个方法是Redisson加锁的核心代码,本质也是通过redis的lua脚本;

加锁原理

[image:D1C0281D-807E-4635-8D01-FD6366C349C0-324-00008A072AF18107/871B4A5F-436D-4055-A80F-176A112F83FE.png]

代码解读:*KEYS[1]*加锁key,*ARGV[2]*加锁的值,*ARGV[1]*看门狗机制的过期时间,internalLockLeaseTime续期时间;

  • 第一个if:如果key不存在,则通过hest去加锁,KEYS[1]加锁key,ARGV[2]加锁的值,pexpire命令设置对key值设置过期时间;

  • 第二个if:key存在的情况,hincrby命令判断是不是自己的线程,如果是自己的线程的情况下,就对已经加锁的线程+1操作,并且设置过期时间,这也是可重入锁的一种实现;

  • 直接return,加锁失败,如果key值不是自己所在的线程则返回过期时间;

解锁原理

Redisson看门狗机制你了解多少

#后端技术学习

前言

谈到Redisson就不得不说Redis了,一想到Redis就不得不想到并发编程锁机制,一想到锁机制那么就不能不考虑一个很头疼的问题,如何保证原子性的问题,高QPS请求量的系统对每次执行数据的原子性由为的关键,保证不了原子性就会导致一系列重复提交的操作,重复的数据导致在某些逻辑运算的时候发生误差;

ACID的特性首先是原子性,原子性永远是放在首位的,所以我们首先要解决的就是接口请求的原子性;

Redis分布式锁的原子性

Redis分布式锁到底能不能保证原子性,这是面试会被经常问到的一个问题。大部分的人回答都是不能保证原子性,但是其中的所以然大家都很模糊,我也一样,但为什么还在用Redis的分布式锁,如何让它可以具有原子性呢?

Redis分布式锁实现

SET NX相信大家都知道是redis实现加锁的一个命令,这里用Jedis封装的Api接口去对redis进行使用,Jedis是Redis官方推荐的面向Java操作Redis的客户段,RedisTemplate是SpringDataRedis中对Redis的封装客户端,方便的就是可以搭配Spring框架使用,如Spring cache

先上代码吧,这是我曾经写的一段关于redis分布式锁的代码,主要用于重复提交的判断,这里我用了jedis的setnx方法,加锁后的返回不为null && 值等于1的时候表示加锁成功,并且调用expire方法对key进行赋过期时间,业务处理完成后进行锁的释放,防止死锁,这里是常规的redis的加锁方式;


/**
 * 分布式事务锁-判断是否请求过
 * 
 * @param key 键
 * @param time 过期时间
 * @return true:存在
 */
@HystrixCommand(fallbackMethod = "isExistFail")
public boolean isExist(String key, int time) {
    Jedis jedis = null;
    try {
        jedis = jedisPoolManager.getJedis();
        String uniqKey = JEDIS_KEYNAME + key;
        String val = jedis.get(uniqKey);
        if (val != null) {
            return true;
        }

        if (lock.tryLock(1, TimeUnit.SECONDS)) {
            try {
                    Long flag = jedis.setnx(uniqKey, LOCAL_VAL);
                if (flag != null && flag.intValue() == 1) {
                    jedis.expire(uniqKey, time);
                } else {
                    throw new ExceptionTyche("加锁失败! ");
                }
            } finally {
                lock.unlock();
            }
        } else {
            log.info("执行Redis超时!直接返回!");
        }
    } catch (Exception e) {
        log.warn("Redis缓存异常! key={} errMsg:" + e.getMessage(), key, e);
    } finally {
        jedisPoolManager.close(jedis); // !!!关闭
    }
    return false;
}

细心的小伙伴可以看到, 我在setnx加锁之前,用了lock.tryLock这个方法,用jdk的锁先尝试进行获取锁,如果没有获取到直接返回,这样就能在一定程度上避免通过redis加锁后,业务逻辑还未执行完锁超时进行释放,导致下次同样的key获取到锁就会出现重复提交的操作

并且使用了HystrixCommand熔断注解,防止在高并发的情况下加锁方法出现异常,对其进行降级,保证业务提交的原子性;

Redisson分布式锁的原子性

关于Redisson是目前使用比较多的一个关于分布式锁的客户端,其主要原理相信大家知道,那就是watchDog机制,俗称“看门狗机制”,由于这种机制能对锁的过期时间进行续期在很大程度上能保证加锁的原子性;

Redisson看门狗机制

前段时间突然遇到了这么一个问题,Redisson锁是统一进行续期的还是分开续期的,之前确实没有考虑过,下面来看下源码具体分析下;

这里我使用的是,redisson3.8.2的版本

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

这个方法是Redisson加锁的核心代码,本质也是通过redis的lua脚本;

加锁原理

代码解读:*KEYS[1]*加锁key,*ARGV[2]*加锁的值,*ARGV[1]*看门狗机制的过期时间,internalLockLeaseTime续期时间;

  • 第一个if:如果key不存在,则通过hest去加锁,KEYS[1]加锁key,ARGV[2]加锁的值,pexpire命令设置对key值设置过期时间;

  • 第二个if:key存在的情况,hincrby命令判断是不是自己的线程,如果是自己的线程的情况下,就对已经加锁的线程+1操作,并且设置过期时间,这也是可重入锁的一种实现;

  • 直接return,加锁失败,如果key值不是自己所在的线程则返回过期时间;

解锁原理

既然有加锁,相对肯定有解锁实现;

  • 第一个if:判断加锁key存不存在,*KEYS[2]*这里代表发布订阅消息的管道名称;

  • 第二个if:判断KEY[1]的ARGV[3]是否存在,*APGV[3]*代表线程id标识,如果不存在则返回null;

  • 第三方if:如果存在将APGV[3]的值减一,如果counter的值相当于线程id标识经过运算后的值大于0,由于是可重入锁,该线程依旧可以获取到锁,重新设置*ARGV[2]*锁过期时间,返回0;

  • del操作是真正的解锁操作,并且通过publish命令发布消息,*APGV[1]*代表消息内容,操作成功后返回1;

  • 解锁失败返回nil,nil相当于Java中的null;

Watchdog锁续期

通过对redisson的加锁、解锁源码分析,相信大家对这块已经有个很清楚的认识, 还有就是只有当前线程才是获取自己的锁,不是当前线程无法获取到锁,就意味着无法进行锁续期的操作 ,由此可证明Redisson锁的续期是分开进行的,commandExecutor.evalWriteAsync的加锁方法比较长,这里就不截出来了,有兴趣的小伙伴可以去追踪看看;

主要续期逻辑就是,例如一个线程加锁成功,就是自动触发Watchdog锁续期机制,后台是一个工作线程,每隔10秒钟的时间会check当前线程是否还持有锁,如果持有锁就将锁的过期时间延长至30秒;

总结

这里也是对之前redisson锁的知识遗漏点的一个学习,结合实际的业务开发使用的案例,来分析锁的底层原理,从而来避免我在使用过程中遇到问题,能有更加清晰的解决思路,理解不对的地方也欢迎大家在评论区提出。

既然有加锁,相对肯定有解锁实现;

  • 第一个if:判断加锁key存不存在,*KEYS[2]*这里代表发布订阅消息的管道名称;

  • 第二个if:判断KEY[1]的ARGV[3]是否存在,*APGV[3]*代表线程id标识,如果不存在则返回null;

  • 第三方if:如果存在将APGV[3]的值减一,如果counter的值相当于线程id标识经过运算后的值大于0,由于是可重入锁,该线程依旧可以获取到锁,重新设置*ARGV[2]*锁过期时间,返回0;

  • del操作是真正的解锁操作,并且通过publish命令发布消息,*APGV[1]*代表消息内容,操作成功后返回1;

  • 解锁失败返回nil,nil相当于Java中的null;

Watchdog锁续期

通过对redisson的加锁、解锁源码分析,相信大家对这块已经有个很清楚的认识, 还有就是只有当前线程才是获取自己的锁,不是当前线程无法获取到锁,就意味着无法进行锁续期的操作 ,由此可证明Redisson锁的续期是分开进行的,commandExecutor.evalWriteAsync的加锁方法比较长,这里就不截出来了,有兴趣的小伙伴可以去追踪看看;

主要续期逻辑就是,例如一个线程加锁成功,就是自动触发Watchdog锁续期机制,后台是一个工作线程,每隔10秒钟的时间会check当前线程是否还持有锁,如果持有锁就将锁的过期时间延长至30秒;

总结

这里也是对之前redisson锁的知识遗漏点的一个学习,结合实际的业务开发使用的案例,来分析锁的底层原理,从而来避免我在使用过程中遇到问题,能有更加清晰的解决思路,理解不对的地方也欢迎大家在评论区提出。

标签:加锁,Redis,看门狗,Redisson,线程,key,机制,续期
From: https://blog.csdn.net/qq_66627105/article/details/144487809

相关文章

  • 自适应选择机制
    自适应选择机制是一种根据当前环境或数据特征自动调整选择策略或参数的过程。以下是对自适应选择机制的详细解释:一、定义与原理自适应选择机制的核心在于其能够根据输入信号、数据特征或环境条件的变化,动态地调整选择策略、参数或方法,以适应不同的场景和需求。这种机制通常涉及......
  • 华为、华三、思科高级网络工程师必经之路(2)我们的爱如同TCP连接,始终可靠,永不掉线——
    欢迎各位彦祖与热巴畅游本人专栏与博客你的三连是我最大的动力以下图片仅代表专栏特色[点击箭头指向的专栏名即可闪现]专栏跑道一➡️网络空间安全——全栈前沿技术持续深入学习 专栏跑道二➡️ 24NetworkSecurity-LJS ​​ ​专栏跑道三 ➡️ MYSQL......
  • 包机制、文档注释javaDoc、用户交互Scanner20241223
    包机制20241223点击src打开设置点击外观取消勾选压缩空的中间软件包、平展软件包创建包点击src点击新建,点击软件包输入新建包名com.pangHuHuStudyJava用别的包里的方法,要先导入包,如果没有导入,可以按住出错的地方按alt+enter.importjava.util.Date;在operator.......
  • 车载网关性能 --- GW ECU报文(message)处理机制的技术解析
    我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师:所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的豁达,往不幸上面喷“......
  • 【python编程】Python的site钩子机制
    Site简介我们知道:Pythonimport时会首先寻找sys.path中列出的路径,类似下面:sys.path['','/usr/local/lib/python36.zip','/usr/local/lib/python3.6','/usr/local/lib/python3.6/lib-dynload','/usr/local/lib/python3.6/site-packages&#......
  • Java的垃圾回收机制介绍、工作原理、算法及分析调优
    Java的垃圾回收(GarbageCollection,GC)是Java虚拟机(JVM)提供的一种自动内存管理机制,用于自动回收不再使用的内存空间,以避免内存泄露和内存溢出等问题。下面主要介绍Java垃圾回收的基本概念、工作原理、算法等。一、JVM内存结构在了解垃圾回收之前,我们需要先了解JVM的内存结构。J......
  • K8s 网络机制
    概述一、Service类型NodePort LoadBalancer ExternalName 二、容器网络机制同一个Node内访问 跨Node间Pod访问 三、Service与Pod关系Pod的定义Service的定义两者之间关系四、Kube-proxy多种模式Userspace模式iptables模式 ipvs模式五、Ingre......
  • QRCNN-Attention多变量时序预测 基于分位数回归的卷积神经网络结合注意力机制的多变量
    目录Matlab基于QRCNN-Attention多变量时序预测基于分位数回归的卷积神经网络结合注意力机制的多变量时序预测效果分析基本介绍订阅专栏只能获取专栏内一份代码。程序设计参考资料Matlab基于QRCNN-Attention多变量时序预测基于分位数回归的卷积神经网络结合注意力......
  • 医院管理系统(HIS系统)如何建立数据同步与一致性机制?
    在HIS系统中建立数据同步和一致性机制对于确保系统数据的准确性、完整性和及时更新至关重要。以下是建立数据同步和一致性机制的一些建议:1、明确数据同步和一致性的目标首先,有必要明确数据同步和一致性的目标,包括确定哪些数据需要同步、同步频率和数据一致性标准。这有助于......
  • 《深入剖析Redisson源码》揭秘Redisson分布式锁原理(可重入锁机制、PubSub可重试机制、
    Hiヽ(゜▽゜)-欢迎来到蓝染Aizen的CSDN博客~......