热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis分布式锁(看门狗)

Redis分布式锁(看门狗),Go语言社区,Golang程序员人脉社

1、锁住对象,并且设置一个过期时间(业务逻辑操作时间一定小于超时时间)

原先能想到的就是这样的一个方案然后代码实现如下:

public static boolean lock(String key, Long expireTime) {    final long expires = Objects.nonNull(expireTime) ? expireTime : 10L;    return (Boolean) redisTemplate.execute((RedisCallback) connection -> {        byte[] locks = key.getBytes();        boolean acquire = connection.setNX(locks, key.getBytes());        // 如果设置过期时间为空就删除key        if (acquire && !connection.expire(locks, expires)) {            connection.del(locks);            acquire = false;        }        return acquire;    });}
目前的案例里面分布式锁主要锁的是新增商品名称,业务就是新增商品而已
@PostMapping("addGoods")@ApiOperation(value = "新增商品", notes = "新增商品")public Result addGoods(@RequestBody Goods goods) {    final String key = "seckill-shopping:" + goods.getName();    boolean lock = RedisUtil.lock(key, 10L);    if (lock) {        log.info("n{} -->获取锁成功", Thread.currentThread().getName());        goods = this.goodsService.insert(goods);        RedisUtil.removelock(key);        return Result.success(goods);    }    log.info("n{} --> 获取锁失败", Thread.currentThread().getName());    return Result.failure("服务暂时无法加载。。。");

使用jmeter开启5个线程迭代两次,看代码其实结果应该都可以猜得出来每一轮迭代只会成功一条数据,其他的都会失败,看看结果确实是这样的:

我们设计的时候默认的过期时间设置为了10s,假如业务操作导致超过了过期时间,我们看看会有什么问题。假设第一个获取到锁的业务操作时间为29s,其他的都是正常执行的看一下结果,第一个请求获取的锁过期了但是业务还在执行中,其他请求可以获取到锁并且可以执行业务,这就出现了超过过期时间锁不住的问题。(但是如果业务逻辑百分之百不会超过过期时间那就没必要续期了)

如果不需要续期但是上面的都只是单次获取失败就失败了,如果有的业务应该是多少时间内尝试获取失败才算失败,所以加上了一个尝试获取时间(getTime单位:秒) 

public static boolean lock(String key, Long getTime, Long expireTime) {    final long gets = Objects.nonNull(getTime) ? getTime : 10L;    LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(gets);    final long expires = Objects.nonNull(expireTime) ? expireTime : 10L;    return (Boolean) redisTemplate.execute((RedisCallback) connection -> {        byte[] locks = key.getBytes();        while (localDateTime.isAfter(LocalDateTime.now())) {            boolean acquire = connection.setNX(locks, key.getBytes());            // 如果设置过期时间失败就删除key            if (acquire && connection.expire(locks, expires)) {                return true;            } else if (acquire) {                connection.del(locks);            }            // 随机休眠几毫秒            int time = random.nextInt(10);            try {                Thread.sleep(time);            } catch (InterruptedException e) {                e.printStackTrace();            }        }        return false;    });}
2、续过期时间(续期)
续期很多都是使用了Redis的看门狗,那么这个看门狗要怎么使用呢?
首先引入Redisson依赖
    org.redisson    redisson-spring-boot-starter    3.9.1
默认配置文件里面数据:
spring:  redis:    database: 0    host: 127.0.0.1    port: 6379    password: 123456
并且使用了自动配置,看门狗就使用了默认的时间

@PostMapping("addGoods")@ApiOperation(value = "新增商品", notes = "新增商品")public Result addGoods(@RequestBody Goods goods) {    RLock rLock = RedisUtils.getRLock(goods.getName());    boolean islock = false;    try {        islock = rLock.tryLock(30, TimeUnit.SECONDS);        if (islock) {            log.info("n{} --> 获取锁成功", Thread.currentThread().getName());            goods = this.goodsService.insert(goods);            if (count == 0) {                ++count;                try {                    log.info("n{} --> 获取到锁的睡眠40s", Thread.currentThread().getName());                    Thread.sleep(40000);                    log.info("n{} --> 获取到锁的醒了", Thread.currentThread().getName());                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            return Result.success(goods);        }    } catch (Exception e) {        log.info("n{} --> 获取锁失败:{}", Thread.currentThread().getName(), e);    } finally {        if (islock) {            rLock.unlock();        }    }    log.info("n{} --> 获取锁失败", Thread.currentThread().getName());    return Result.failure("服务暂时无法加载。。。");}
对应有很多加锁的方法,只有tryLock方法才会续期的哦。
对应tryLock方法有:
rLock.tryLock(); 默认锁定30s,一次获取锁
rLock.tryLock(20, TimeUnit.SECONDS);默认锁定30s,20s内获取不到锁就返回失败
rLock.tryLock(20,60, TimeUnit.SECONDS); 默认锁定30s,20s内获取不到锁就返回失败,60s锁自动过期。
运行以后可以发现

分布式锁相关的问题还有很多,由于使用的是redis就要考虑一个问题了,就是分布式锁还要考虑redis部署的问题,要使用分布式锁的前提你要把相对应的问题考虑清楚,否则上线都是问题了。

以上的是小辉对分布式锁理解以及使用,如果代码要用到线上项目请自己测试后评估后使用,因为最近看到了使用开源代码引发的线上事故,如果不是很了解的东西尽量少用或者不用,除非它是一个成熟的东西

                                      文章同时会更新到公众号,觉得对你有帮助或者有用的可以关注一下哦 


推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
author-avatar
dfpkgih
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有