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

网站联盟名词解释抖音seo优化软件

网站联盟名词解释,抖音seo优化软件,安徽整站优化,郴州网站开发公司一、前言 本期我们聊一下缓存击穿,其实缓存击穿和缓存穿透很相似,区别就是,缓存穿透是一些黑客故意请求压根不存在的数据从而达到拖垮系统的目的,是恶意的,有针对性的。缓存击穿的情况是,数据确实存在&…

一、前言

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

二、问题描述

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

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

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

        还有别的原因,缓存搭建了主从结构,主从的数据同步存在延时,导致客户端请求从节点时拿不到数据,或者是主节点使用了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/291760.html

相关文章:

  • 哪家公司做网站结算好如何免费制作自己的网站
  • 手机怎么创网站免费下载网站设计的毕业论文
  • 体检营销型网站营销网站案例
  • 网站的建设部署与发布人力资源培训机构
  • 打不开网站怎么办html模板网站
  • 那个网站上找工程造价私活做长春seo代理
  • 如何设置企业网站跨境电商培训机构哪个靠谱
  • 在什么网站能帮人做ppt微信营销推广
  • 阿里云服务器可以做下载类网站吗东莞关键字排名优化
  • 青羊区建设局网站百度广告买下的订单在哪里找
  • 广告建设网站建设整合营销沟通
  • 网站开发卖东西快速排名生客seo
  • 政府门户网站建设背景百度新闻排行榜
  • 单页网站怎么做外链优秀的营销策划案例
  • 网站设计联系方式杭州seo网络推广
  • 长春互联网推广武汉seo
  • 什么游戏不用登录直接玩seo规则
  • 万家建设有限公司网站营销战略有哪些内容
  • 有哪些网站用java做的20个排版漂亮的网页设计
  • 怎么根据别人的网站做自己的网站360网站排名优化
  • 做企业平台的网站有哪些凡科网免费建站官网
  • php做网站的分站百度公司的企业文化
  • 用ps怎么做网站导航条常州网站建设优化
  • 广州英铭网站建设惠州seo公司
  • 西安网约车租赁公司哪家好sem优化技巧
  • 在西部数码上再备案一个网站ftp网络营销软文范例300字
  • 社保个人网页登录网络优化的流程
  • 什么做网站做个多少钱啊市场调研的基本流程
  • wordpress两个网站同步站长工具seo综合查询网
  • wordpress接入微信支付网站推广的优化