当前位置: 首页 > wzjs >正文

网站建设的方法有哪些方面小语种网站建设公司

网站建设的方法有哪些方面,小语种网站建设公司,文山专业网站建设哪家好,低代码开发app一、前言 本期我们聊一下缓存击穿,其实缓存击穿和缓存穿透很相似,区别就是,缓存穿透是一些黑客故意请求压根不存在的数据从而达到拖垮系统的目的,是恶意的,有针对性的。缓存击穿的情况是,数据确实存在&…

一、前言

        本期我们聊一下缓存击穿,其实缓存击穿和缓存穿透很相似,区别就是,缓存穿透是一些黑客故意请求压根不存在的数据从而达到拖垮系统的目的,是恶意的,有针对性的。缓存击穿的情况是,数据确实存在,只不过因为某些原因导致缓存中数据消失了,导致请求到达了数据库,从而导致数据库的崩,下面我们看看这个问题是怎么个情况。

二、问题描述

        我们之前也介绍过,缓存和数据库双写一致的事情,一般是如果缓存中不存在的话,就从数据库中再查询一遍,然后将查询到的数据维护到缓存中,等下次请求的时候,就能直接从缓存中获取到了,正常是这么个套路,没毛病。但是我们之前也介绍过,有一些热点数据,在启动的时候就需要加载到缓存中,热点数据的特点就是访问频繁,为了减少数据库压力才放到缓存中,那么如果是热点数据在缓存中失效,那么数据库访问压力就会剧增,情况再糟糕一点,热点数据访问量巨大,那么数据库被拖垮那也是板上钉钉的事情。

        那么热点数据为什么会失效?

        其中一个原因是缓存过期了,热点数据被设置了过期时间,一旦过期,大量请求达到数据库,压垮数据库。

        还有别的原因,缓存搭建了主从结构,主从的数据同步存在延时,导致客户端请求从节点时拿不到数据,或者是主节点使用了rdb备份方式,恰好宕机丢失了一部分数据中包含了热点数据等等,缓存失效的可能原因我们先暂时讨论这么多,这不是我们本次讨论的内容。

三、解决方案

3.1、热点数据设置永不过期

        对于热点数据,如果担心因为缓存过期引起击穿,我们可以尝试不设置过期时间,这样就不用担心因缓存过期导致缓存击穿了。

        不设置过期时间是个好办法,不过我想既然给设置了过期时间,那么说明确实需要设置过期时间,那么在这种情况下,不设置过期时间就不适用了,我们采取另一种方案。

3.2、互斥锁方案

       我们再唠叨一下缓存击穿的特点,大量请求达到数据库导致数据库崩溃。那我们简单分析一下,核心问题是大量请求到达数据库,而且这些请求的都是同一个key的数据。

        基于上述两点可以想想办法:

        首先我们可以基于同一个key进行加锁,保证同一时间只会有一个线程访问数据库。如果某个线程先获取到了锁,先进行一次缓存读取,如果确实没有数据,再去访问数据库,将数据库中的数据加载到缓存中并返回,之后将锁释放。依次往复。为什么要这么做,数据库访问过一次之后,缓存中就会维护好数据,其他的请求当然也没有再访问数据库并维护缓存的必要了。

    @Testpublic void cachePenetrate() throws Exception{int countNumber = 5;CountDownLatch countDownLatch = new CountDownLatch(countNumber);//查询数据for (int i = 0; i < countNumber; i++) {new Thread(()->{Long id = 3L;String cacheKey = "mutualExclusion:"+id;String lockKey = "mutualExclusionLock:"+id;//线程从缓存中获取数据Object valObj = redisTemplate.opsForValue().get(cacheKey);String code = "";if(Objects.isNull(valObj)){code = mutualExclusion(cacheKey,lockKey, id);}else {code = valObj.toString();}System.out.println(Thread.currentThread().getName()+"已获取到值:"+code);countDownLatch.countDown();},"线程"+(i+1)).start();}countDownLatch.await();}/*** 功能描述: 互斥锁解决缓存穿透* @Author:huhy* @Date: 2025/4/10 22:38*/private String mutualExclusion(String cacheKey,String lockKey,Long id){//开启分布式锁RLock lock = redissonClient.getLock(lockKey);try {lock.lock();//在获取锁之后,从缓存中获取一次数据,看看是否已有其他线程写入Object valObj = redisTemplate.opsForValue().get(cacheKey);//如果缓存中有数据,则直接返回if(Objects.nonNull(valObj)){System.out.println("缓存中已有数据,线程【"+Thread.currentThread().getName()+"】未进行数据库查询");return valObj.toString();}System.out.println("缓存中没有数据,线程【"+Thread.currentThread().getName()+"】正在进行数据库查询并设置缓存");TSCodeRule tsCodeRule = codeRuleService.selectTSCodeRuleById(id);//设置过期时间为5秒redisTemplate.opsForValue().set(cacheKey,tsCodeRule.getCodePrefix(),5,TimeUnit.SECONDS);}finally {lock.unlock();}return null;}

       

        测试代码中,设置了5个线程,只有第一个线程进行了数据库查询,后边的线程都读取到了线程1设置好的缓存数据,减少了数据库的访问压力,算是解决了缓存击穿的问题。

        T哥:什么叫算是解决了,那到底解决没啊。

        小永哥:被你发现了,解决是解决了,但是我们设置缓存的初衷是什么?不就是看中它快嘛,热点数据本来访问量就大,放到缓存本来就是为了快速响应的,现在好了,加上了锁,都串行化了,那势必会牺牲掉性能。

        T哥:别卖关子了,我知道你还有招,赶紧的吧........

        小永哥:好的。

3.3、逻辑过期方案

        逻辑过期的意思是:不再设置过期时间,将过期时间与值一起保存到redis中,当应用程序读取到缓存中值的时候,将值中包含的过期时间读取出来进行校验,如果已过期,那么开启新的线程异步去维护缓存数据,而本次还是返回旧数据。这么做的好处是应用程序依旧能保持很高的响应,缺点就是,如果数据库中数据被修改过的话,无法及时返回最新的数据。

        

       

    @Testpublic void logicExpireTest() throws Exception{int countNumber = 50;CountDownLatch countDownLatch = new CountDownLatch(countNumber);//查询数据for (int i = 0; i < countNumber; i++) {new Thread(()->{random = new Random();try {TimeUnit.SECONDS.sleep(random.nextInt(3) + 1);}catch (Exception e){}System.out.println(Thread.currentThread().getName()+"已获取到值:"+getCacheValueByKey(4L));countDownLatch.countDown();},"线程"+(i+1)).start();}countDownLatch.await();}String getCacheValueByKey(Long id){//从缓存中获取值String cacheKey = "logicExpireTest:"+id;String jsonStr = redisTemplate.opsForValue().get(cacheKey).toString();Map<String,String> cacheCodeMap = JSON.parseObject(jsonStr,Map.class);//校验是否已超时long startTime = Long.parseLong(cacheCodeMap.get("startTime"));long expire = Long.parseLong(cacheCodeMap.get("expire"));boolean isExpire = (System.currentTimeMillis() - startTime) > expire;//如果超时,另起线程去维护redisif(isExpire){new Thread(()->{TSCodeRule tsCodeRule = codeRuleService.selectTSCodeRuleById(id);Map<String,String> codeInfoMap = new HashMap<>();codeInfoMap.put("code",tsCodeRule.getCodePrefix());codeInfoMap.put("expire",String.valueOf(3000));codeInfoMap.put("startTime",String.valueOf(System.currentTimeMillis()));redisTemplate.opsForValue().set(cacheKey,JSON.toJSONString(codeInfoMap));}).start();}//始终返回从缓存中读取到的数据return cacheCodeMap.get("code");}

        经过运行测试代码,我们可以看到,有的线程是新值,有的是旧值。

四、结语

        缓存穿透我们讨论了三种解决方式,这两种方式并没有谁比谁更优秀,没有哪种解决方案是完美的,只有适合应用场景的解决方案,在日常应用时需要我们灵活选择。

http://www.dtcms.com/wzjs/811427.html

相关文章:

  • 做网站廊坊大规模网站开发语言
  • pinterest网站怎么进一站式网站开发服务平台
  • vps服务器中的网站不显示图片深圳关键词优化
  • 做本地的门户网站有什么可以在线做数学题的网站
  • 快捷的网站建设排行榜安卓下载软件app
  • 网站建设的安全性伊春市住房和城乡建设局网站
  • 遵义门户网站做外贸都做哪些网站好免费
  • 发卡网站搭建简述企业网站如何推广
  • 网站开发视频会议插件做一个个人网站
  • 现在网站建设还用测浏览器吗自己做一个模版网站是怎么做的
  • 丰金网络 做网站注册企业公司流程及费用
  • 网站建设和运行管理办法找团队做网站
  • 如何做品牌网站设计凡科网站建设如何植入代码
  • wordpress 获取当前分类id结构优化是什么意思
  • 济南网站建设公司哪个好如何做自己的网站系统
  • 公司建设网站费用属于什么费用做微信小程序的软件
  • 天台建设局网站德阳定制建站网站建设制作
  • 武昌有专业做网站学做衣服的网站有哪些
  • 网络服务提供商漳州seo网站快速排名
  • 大众点评如何做团购网站网上推广手段包括
  • 高新区微网站建设wordpress图片如何存储
  • 虚拟主机建设网站绑定域名网站设计费
  • 企业网站建设怎么选择空间网站开发里程碑
  • 收费网站建设视频教程免费下载网站免费建站系统 六
  • 网站开发设计前景网上购物网站开发报价
  • 查询数据的网站怎么做云南移动和生活app安装
  • mvc做的网站wordpress格子主题
  • 万网网站备案婚纱网站html模板
  • 描述建设一个网站的具体流程软件外包公司为什么不好
  • 做展示型网站个人建设网站维护费是多少