• redis分布式锁的应用


    redis 作为分布式锁的东西 分布式锁的应用
    redis,zk,数据库这些都可以实现分布式锁
    我们今天主要基于redis实现的分布式锁,而且要求性能要好
    基于一个小的业务场景来说,就比如说秒杀中的减库存,防止超卖
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    这种代码就会有并发问题,比方说3个线程  同时查出来 之后会set 299  此时就超卖了
    这就是我们典型的超卖问题,我们可以加锁,比如说我们常见的sy,JVM进程级别的锁
    
    • 1
    • 2

    在这里插入图片描述

    这样就可以解决我们的问题,如果说我们此时上线部署之后就一台服务器,也就一个tomcat 
    单机环境 是没有问题 假设我们做集群项目的时候 此时就会出现问题
    我们的项目基本上都是 基于nginx 进行转发,利用nginx做负载均衡,
    在nginx的upstream中配置负载均衡的地址
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    一般来说我们都会搞这些集群架构部署,这种场景下我们jvm 级别锁就不可用了
    我们可以模拟高并发场景利用jmeter基于高并发下发请求
    jmeter--->nginx---->tomcat1/tomcat2
    发现如果此时利用jvm级别的锁就会出现问题
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    一般情况下这种问题要解决的话 就用分布式锁 分布式锁 可以用redis
    我们一般使用redis的setnx来实现分布式锁
    基于setnx命令我们就可以实现一个分布式锁,在redis这边 只会有1个请求执行成功
    这样我们就写完了
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    我们基于这种简单的setnx 实现的分布式锁有什么问题呢
    Q1 如果我第一个线程拿到锁执行一半的时候 就会抛异常 抛异常之后 我就不会delete掉了
    这个时候就相当于死锁了,key永远在redis中  其他线程要想来执行就会执行不成功
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    我写个try catch finally 意思是如果跑异常了 我还可以执行redis.delete 	
    如果现在执行一半后 客户端宕机了,或者被运维重启了,呢么此时finally也是不能被执行的,我们可以设置一个超时时间,比方说10s,
    
    • 1
    • 2

    在这里插入图片描述

    我们可以加个超时时间,意味着如果你业务宕机了,过段时间 redis内部自己就释放锁了
    如果并发特别大的情况下.这种代码也会造成超卖,在并发情况下 接口的响应可能会变慢
    
    如果线程一执行了一半,超时时间到了, 这个时候线程2就会进来,然后此时线程一就会吧线程2的这个锁解开
    线程1 删除(释放了)了线程2的锁  此时就会出现问题
    出这个问题的根本点就在于  我自己加的锁被别人释放了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    我们可以加个uuid就是说 我只能释放我自己加的锁,这个时候的代码就很完善了
    
    • 1

    在这里插入图片描述

    假设一个线程枷锁成功了执行到这行代码的时候,卡顿一会,我们的10s到期了
    其他线程又可以基于这个Lock进行加锁,这个时候线程1还是释放了线程2的锁
    所以我们要保证这2行代码的原子性
    
    我们的业务没有执行完毕 锁的超时时间就结束了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    针对于分布式锁 有个锁续命机制 
    分线程给锁进行续命,判断主线程有没有业务执行完毕,如果没有结束就续命
    每过10s之后就续命,我的主线程一直执行 我的锁就不会失效,因为他一直被分线程做续命操作
    以后我主线程要是把锁释放了,分线程会判断锁还被主线程持有 如果持有 就会做续命操作
    如果不持有就不再跑任务了
    Redisson  就实现了这种机制 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    lock.lock 就可以获取得到锁了
    Lock.unLock 加锁 解锁
    https://www.cnblogs.com/xiaoyangabc/p/16906922.html
    redis枷锁的核心流程, 假设有2个线程同时都是一个key执行  redis调用他的lock方法
    只有1个线程执行成功,假设线程1执行成功。 线程2 执行没有成功
    他会whlie循环自璇  尝试加锁
    线程1 加锁成功 他会另外开启一个分线程,分线程就会对这个key 进行续命,
    这就是整个redis分布式锁续命的核心业务流程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    redis分布式锁底层是基于Lua脚本来写的,
    lua脚本,减少网络开销。可以批量执行redis命令,类似于管道可以把一批命令打包发给redis 服务端去执行
    比如说原来有4条命令,我就需要发送4次远程交互(网络调用)
    但是我用管道或者lua脚本的话 就只需要一次网络调用
    对于Lua脚本也一样,假设我有10条redis命令,我也可以放到lua脚本来一次性发给服务端去执行
    lua脚本是支持原子操作的,一段Lua脚本,要么同时成功,要么同时失败
    lua脚本都执行完毕 之后 其他命令才可以执行(因为redis服务端是单线程来执行任务的)
    我这个命令执行的中间是不可以被其他线程插入的
    Lua  支持事务在redis中可以执行lua脚本
    用lua脚本是个原子操作
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    在这里插入图片描述

    redis分布式锁的原理,当多个线程进行抢锁时候,只有一个线程来设置成功,其他没有抢到锁的线程就会while自旋尝试加锁,通过lua脚本进行加锁,加锁成功后就会对其进行续命,加锁失败就会自璇,续命锁
    (Lua脚本进行续命) 每次续命1/3(判断主线程持有的呢吧锁是否还存在,如果存在我就进行续命,吧主线程的超时时间重新设置为30S ,如果不存在,我就结束)
    
    说白了redis实现分布式锁的核心东西也就完成了,基本上是基于Lua来实现的  借助redis的单线程帮我们实现原子性.来解决并发问题
    
    • 1
    • 2
    • 3
    • 4
    
    当我们其他线程如果没有加锁成功,lock 没有加锁成功会怎么办.假设有10个线程while循环枪锁 他的cpu 就会100%,如果说我们redis 没有抢到锁 他自选再去加锁 他是怎么来做的
    其他线程会返回锁剩余加锁时间的剩余时间 并且阻塞让出cpu
    
    比如说第一个线程执行了5S之后
    假设我我第二个线程会尝试的过来加锁 如果没有加锁成功会再这里等25S  阻塞等待会让出cpu
    25s过后之后再尝试加锁while循环间断性的加锁
    假设有1000个线程来了同时超时 同时while循环  此时是非公平锁 也就是redis 默认 是非公平锁
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    所以 多个线程来抢锁时,底层会基于lua脚本进行加锁,但是只有一个线程来加锁成功,抢锁成功后后台开启一个分线程来对其进行续命,其他线程如果没有抢到锁 会while尝试加锁 但是 并不是死循环
    而是会阻塞等待,返回第一次尝试加锁返回的时间,并且此时会让出cpu片段
    
    如果此时业务时间比较快,快速吧这把锁释放了. 呢我其他线程不能一直阻塞 在解锁的方法中有一个唤醒机制 通过redis的发布订阅 他会往Queue发消息
    没有加锁成功的线程会去监听Queue,呢么其他线程就会唤醒阻塞  继而继续while循环继续抢锁
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    redis的数据冷热处理
      
    
    • 1
    • 2

    在这里插入图片描述

    中小型公司使用redis作为缓存,会将数据放入redis中进行缓存,用来提升系统的并发能力
    
    • 1

    在这里插入图片描述

    如果你的系统流量不是特别大 这么用就可以,但是如果并发量大的话  就会有redis 缓存问题
    呢么在高并发情况下有什么问题  例如京东
    后台商品很多,我的redis 里面会有很多缓存 呢么我的redis容量要很大
    呢对于我们redis ,整个线上数据上亿 你丢到redis中对我们redis存储容量是很大的
    我们真正的电商网站 真正高频访问的电商  不到1%  大量商品都是冷门商品
    我没有必要吧很少去访问的商品也丢到缓存  浪费我们的资源
    其实我们真正用缓存的目的是尽可能吧经常访问的 热点缓存 尽量在缓存中多呆一会
    冷门数据 不用一直呆在缓存中
    所以我们要对redis的数据做冷热分离
    1、 我们可以放置redis 的时候加个随机事件   比如说1天, 在get的时候如果在redis中找到的话 
    我们继续给他延迟
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    在这里插入图片描述

    对于不怎么访问的冷门商品在缓存中存储1天就失效了,对于我们一直在访问的商品内存 尽可能的一直呆在缓存中 这样会对我们数据库的请求会大大减少.呢所以在查询缓存做一个读取延期
    如果我这么来做的话,对于每天都来访问的商品会一直在我们缓存中.那些不怎么访问的商品可能也就上架完毕就不在缓存中,实际上我就实现了数据的冷热分离,热点数据 我尽可能的留在缓存中,冷门的数据 不会再缓存中,简单方案的冷热数据分离
    一般情况下,大规模数据我们要做一些数据的冷热分离 让热数据尽可能丢到缓存,而且要常驻缓存
    冷数据可能要查数据库的,让数据库资源就可以给其他模块用了
    
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1.为什么要用多级缓存  优点 缺点
    2.什么场景下要用到多级缓存
    我们一般会使用 缓存架构
      一般公司会使用通过nginx+lua(openresty)+本地缓存+redis这种三级缓存来处理
      如果本地缓存发生改变可以发送mq或者通过zk 可以达到一致性
    
    使用本地缓存 减少读压力
    基于本地缓存的缺点
    Echache jvm级别缓存  存储热点数据,
    Echache 落地 mysql (或者文件中)
    数据不一致我们只需要保证他最终一致性就可以了  比如说缓存改变后 发个mq 
    或者通过zk来做
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    在这里插入图片描述

    热点探测服务的原理和实现
    我们jvm 级别的数据不支持大数据存储, 所以对于热点数据我们要进行发掘再进行存储
    
    • 1
    • 2

    在这里插入图片描述

    热点数据就会满足2个条件  有限时间 流量高聚
    基于这种有预期的热点 我们可以提前 在这种热点开起之前 我们有很多方式进行优化
    比如说对服务进行扩容和降级
    基于没有热点的这种场景 我们需要做探测,探测之后放到redis中
    呢么没有预期的热点
    1.黑客攻击 
    2.突然爆火的商品 或者突然大卖的商品 比如说疫情下的口罩
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    滑动窗口 对于我们热点数据的探测和发现
    
    • 1

    在这里插入图片描述

    对数据层次的风险  瞬时高并发请求
    对应用服务的风险  每个服务的处理是有限的
    所以我们需要这么一套热Key的检测机制 来通过对需要检测的热key 进行
    发掘
    这就是我们使用热点探测的好处,主要是基于滑动时间窗口的计数器来做,比如说我可以设置一个规则
    在1分钟内出现10次的商品 我就认为他是热点数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

  • 相关阅读:
    在 vue-cli 构建的项目中配置使用资源CDN,加速我们的项目
    【算法-贪心】无重叠区间-力扣 435 题
    计算机毕业设计Java短视频网站(源码+系统+mysql数据库+lw文档)
    IP-Guard申请外发流程说明步骤
    Structured Streaming 编程模型
    编程语言常识
    win11自带矩形块截屏、录屏、视频编辑等功能
    【节能学院】剩余电流动作继电器在浴室中的应用
    SpringBoot 整合 Dozer 映射框架
    vertx学习总结5
  • 原文地址:https://blog.csdn.net/weixin_43689953/article/details/133981165