谈及分布式系统的时候,很多企业都会使用到分布式锁,分布式锁的实现方案目前主要是存在两种,redis实现和zookeeper实现。

redis实现方案是多个线程相互竞争,在redis的某一个节点内创建一个键值对,谁能创建成功谁就获取到了锁。锁的释放就是删除当前线程创建的键值对,交给剩余线程去争抢。

   /**     * 应该有两个时间  一个是redis中的键失效时间   一个是执行是循环的跳出时间     * @param key     * @param expire     * @return     */    @Override    public Lock tryLock(String key, int expire, int waitime) {        Boolean success;        Long start = System.currentTimeMillis();        Long end = System.currentTimeMillis() + (waitime * 1000);        Long  number = 0L;        Lock lock = new Lock(Lockeys+key , UUID.randomUUID().toString() , 0L);        while(true){            success = redisTemplate.opsForValue().setIfAbsent(lock.getKey(),lock.getValue(),expire, TimeUnit.SECONDS);            if(success == null){                //此处应该抛出异常 获取锁失败                throw  new RuntimeException("获取锁失败");            }            if(success){                break;            }            //等待时间太长自动释放            Long curtime = System.currentTimeMillis();            if(curtime>end){                break;            }            try {                Thread.sleep(100);  //休眠100毫秒                number++;//也可以根据自旋的次数来选择释放            } catch (InterruptedException e) {                e.printStackTrace();            }        }        Long locktime = System.currentTimeMillis();        lock.setLocktime(locktime-start);        lock.setFalg(success);        return lock;    }

  tryLock方法试图去获取锁,获取成功返回true,获取失败返回false。上面的代码主要的封装一个Lock对象,对象中存在的属性是键值对、锁的获取时间等。请求redis的原子操作类去试图创建一个有限时间的键值对。创建成功的线程返回true执行后续的业务逻辑,未获取锁的线程不断在轮询去请求redis试图获取锁,所以线程设置了休眠100毫秒,减少不必要的线程不断的轮询redis。不断轮询的线程不可能一致让它阻塞在此,所以我们这边设置了一个时间,线程等待一定的时间未拿到锁之后,直接返回false。

锁释放:

 /**     * 为了防止锁释放的不是当前锁,需要校验value     * @param lock     * @param     * @return     */    @Override    public Boolean unlock(Lock lock) {        String value = (String) redisTemplate.opsForValue().get(lock.getKey());        if(value.equals(lock.getValue())){           return redisTemplate.delete(lock.getKey());        }else {            return false;        }    }

锁的释放其实就是在redis中删除当前线程创建的键值对,怎么保证删除对应的键值对是当前线程创建的呢?我们这边比较了一个key值对应的value值,只有两者相同才会执行删除操作。

使用redis的分布式锁绕不开的一个问题就是业务逻辑执行超时后,锁自动释放,所以就无法保证原子性操作。Redis的Liberary中提供了一个第三方的插件Redisson。其大致流程如图所示:

redisson存在一个watch(看门狗)机制,当前业务逻辑执行超时还未释放锁的时候,会定期延长锁的超时时间。

限流对于分布式系统而言是绕不开的问题,redis提供的几种限流的实现方式

(lua脚本实现原子操作)

限流算法:令牌桶算法、漏桶算法

令牌桶算法:存在一个定时任务不断的向桶里面发送令牌,桶里面溢出的话,令牌会丢弃。

一个请求进来会首先去桶中获取令牌,令牌可以获取多个,获取到令牌后才能转发请求,未获取到令牌,请求丢弃。

漏桶算法:

以一定的速率向桶中放置令牌,然后一定的速率流出。突发的大批量请求不适合使用漏桶算法。

lua脚本,通过lua实现redis令牌增加的原子操作

--lua 下标从 1 开始-- 限流 keylocal key = KEYS[1]-- 限流大小local limit = tonumber(ARGV[1])-- 获取当前流量大小local curentLimit = tonumber(redis.call('get', key) or "0")if curentLimit + 1 > limit then    -- 达到限流大小 返回    return 0;else    -- 没有达到阈值 value + 1    redis.call("INCRBY", key, 1)    -- EXPIRE后边的单位是秒    redis.call("EXPIRE", key, 10)    return curentLimit + 1end

入参key值和limit限制,如若操作数量则返回0,没有超过限制则Key对应得数量+1。设置key值得过期时间10秒。

我是凯腾凯,互联网浪潮下一枚苟且偷生的程序员

redis获取存在的键值_Redis 分布式锁、限流相关推荐

  1. redis setnx 分布式锁_Redis 分布式锁PHP

    Redis 分布式锁的作用 在单机环境下,有个秒杀商品的活动,在短时间内,服务器压力和流量会陡然上升.这个就会存在并发的问题.想要解决并发需要解决一下问题 1.提高系统吞吐率也就是qps 每秒处理的请 ...

  2. Redis教程:NoSQL键值存储

    课程大纲 Redis是使用ANSI C编写的具有可选持久性的开源,网络化,内存中键值数据存储.根据DB-Engines.com的月度排名,Redis是最受欢迎的键值存储. 它的名字意思是远程字典服务器 ...

  3. 【Redis】Redis 哈希 Hash 键值对集合操作 ( 哈希 Hash 键值对集合简介 | 查询操作 | 增加操作 | 修改操作 )

    文章目录 一.哈希 Hash 键值对集合 二.查询操作 1.Redis 中查询 Hash 键值对数据 2.查询 Hash 键是否存在 3.查询 Hash 中所有的键 Field 4.查询 Hash 中 ...

  4. C#递归获取JSON所有键值对

    因工作需要,我需要获取JSON所有键值对. 这里我使用List存储,因为有键冲突,但是要求是所有键值对都需要,不理会冲突,所以没有使用字典. public static List<string& ...

  5. map中获取数组_如何从php多维数组中获取特定的键值?

    点击蓝字关注我们!每天获取最新的编程小知识! 源 / php中文网      源 / www.php.cn 在这篇文章中,我们将给大家介绍如何在php中从多维数组中获取特定的键值数组.这里我们将使用a ...

  6. Redis应用详解(一)分布式锁

    1. 前言 在某些场景中,多个进程必须以互斥的方式独占共享资源,这时用分布式锁是最直接有效的. 随着技术快速发展,数据规模增大,分布式系统越来越普及,一个应用往往会部署在多台机器上(多节点),在有些场 ...

  7. 【2020尚硅谷Java大厂面试题第三季 04】Redis 9种数据类型使用场景,分布式锁演变步骤,lua脚本,redis事务,Redisson,Redis内存占用,删除策略,内存淘汰策略,手写LRU

    1.安装redis6.0.8 2023 02 02 为:redis-7.0.8.tar.gz 2.redis传统五大数据类型的落地应用 3.知道分布式锁吗?有哪些实现方案?你谈谈对redis分布式锁的 ...

  8. Redis面试常问3 如何实现分布式锁 记住Redis的原子性

    Redis面试常问3 如何实现分布式锁 上面的伪代码有问题 从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改: http://redisdoc.com/string ...

  9. 深度解析串行并发并行,开发人员需彻底搞懂丨mysql|redis|skynet|协程|索引|读写分离|分布式锁|主从同步

    深度解析串行并发并行,开发人员需彻底搞懂 视频讲解如下,点击观看: 深度解析串行并发并行,开发人员需彻底搞懂丨mysql|redis|skynet|协程|索引|读写分离|分布式锁|主从同步丨C/C++ ...

最新文章

  1. 查询Oracle中字段名带.的数据
  2. 使用plsql连接远程oracle数据库配置
  3. 什么是集群(cluster)
  4. 知识图谱数据构建的“硬骨头”,阿里工程师如何拿下?
  5. css3波浪纹路_使用CSS3实现的波浪分隔线
  6. SpringBoot:搭建第一个Web程序
  7. mybatisplus批量插入原理_Word如何批量打印请柬、奖状、桌牌?一键批量制作就这么简单...
  8. FPGA资源评估方法
  9. cgdb 不显示源码问题
  10. 利用CNN和迁移学习方法识别植物叶片疾病
  11. Guava学习笔记:Immutable(不可变)集合
  12. python bootstrap 中位数_【机器学习】Bootstrap详解
  13. php 如何开发oa系统,如何开发oa系统
  14. c语言编程中分数怎么表示,用C语言编程平均分数
  15. C语言sb代码,10个重要的算法C语言实现源代码
  16. 关于电子科技大学学生用餐情况的一些调查
  17. zabbix触发器通过钉钉发送警报
  18. 【原理】Basic Integer Overflows
  19. 微信公众号怎么生成能追踪效果的二维码?
  20. 基于Java毕业设计校园面包超市系统源码+系统+mysql+lw文档+部署软件

热门文章

  1. 关于移动安全的一点总结
  2. 常用端口号及对应服务
  3. 安装saltstack遇到的问题锦集
  4. JavaScript中this指针指向的彻底理解
  5. ogg启动报错libnnz11.so: cannot open shared object file
  6. JavaScript常用验证代码(正则表达式)(转自cnblogs)
  7. Node.js 沙箱易受原型污染攻击
  8. VirusTotal 共享8000万勒索软件样本分析数据库
  9. 微软称伊朗国家黑客攻击美国国防技术公司
  10. 谷歌研究员发现新的 iOS 安全系统