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

framework7做网站有什么网站可以做电台

framework7做网站,有什么网站可以做电台,做网站茶叶首页标题怎么写,自适应h5网站模板前言:本节包含常见redis缓存问题,包含缓存一致性问题,缓存雪崩,缓存穿透,缓存击穿问题及其解决方案 1. 缓存一致性 我们先看下目前企业用的最多的缓存模型。缓存的通用模型有三种: 缓存模型解释Cache Asi…

前言:本节包含常见redis缓存问题,包含缓存一致性问题,缓存雪崩,缓存穿透,缓存击穿问题及其解决方案

1. 缓存一致性

我们先看下目前企业用的最多的缓存模型。缓存的通用模型有三种:

缓存模型解释
Cache Aside

由缓存调用者自己维护数据库与缓存的一致性

查询时:命中则直接返回,未命中则查询数据库并写入缓存

更新时:更新数据库并删除缓存,查询时自然会更新缓存

Read/Write Through

数据库自己维护一份缓存,底层实现对调用者透明

查询时:命中则直接返回,未命中则查询数据库并写入缓存

判断缓存是否存在,不存在直接更新数据库。存在则更新缓存,同步更新数据库

Write Behind Caching读写操作都直接操作缓存,由线程异步的将缓存数据同步到数据库

目前项目中中使用最多的是Cache Aside模式,因为实现起来非常简单。

在Cache Aside模式中,以下有两点需要注意:

1.在对数据库进行增删改操作时,需要加入清理缓存逻辑

在数据库进行增删改等操作时,数据库中数据会发生变化,但是Redis中缓存的数据未发生变化从而导致数据库和Redis中的缓存的数据不一致,故而在对数据库进行操作时,需要加入清理缓存逻辑来清理Redis中对应的未同步缓存数据

2.先更新数据库再删除缓存的方案

异常情况说明:

  • 线程1查询缓存未命中,于是去查询数据库,查询到旧数据

  • 线程1将数据写入缓存之前,线程2来了,更新数据库,删除缓存

  • 线程1执行写入缓存的操作,写入旧数据

       可以发现,异常状态发生的概率极为苛刻,线程1必须是查询数据库已经完成,但是缓存尚未写入之前。线程2要完成更新数据库同时删除缓存的两个操作。要知道线程1执行写缓存的速度在毫秒之间,速度非常快,在这么短的时间要完成数据库和缓存的操作,概率非常之低。

面试题如何保证缓存的双写一致性

:缓存的双写一致性很难保证强一致,只能尽可能降低不一致的概率,确保最终一致。我们项目中采用的是Cache Aside模式。简单来说,就是在更新数据库之后删除缓存;在查询时先查询缓存,如果未命中则查询数据库并写入缓存。同时我们会给缓存设置过期时间作为兜底方案,如果真的出现了不一致的情况,也可以通过缓存过期来保证最终一致。

追问:为什么不采用延迟双删机制?

:延迟双删的第一次删除并没有实际意义,第二次采用延迟删除主要是解决数据库主从同步的延迟问题,我认为这是数据库主从的一致性问题,与缓存同步无关。既然主节点数据已经更新,Redis的缓存理应更新。而且延迟双删会增加缓存业务复杂度,也没能完全避免缓存一致性问题,投入回报比太低。


2. 缓存穿透

什么是缓存穿透呢?

我们知道,当请求查询缓存未命中时,需要查询数据库以加载缓存。但是大家思考一下这样的场景:

如果我访问一个数据库中也不存在的数据。会出现什么现象?

        由于数据库中不存在该数据,那么缓存中肯定也不存在。因此不管请求该数据多少次,缓存永远不可能建立,请求永远会直达数据库。

        假如有不怀好意的人,开启很多线程频繁的访问一个数据库中也不存在的数据。由于缓存不可能生效,那么所有的请求都访问数据库,可能就会导致数据库因过高的压力而宕机。


2.1 缓存空值

简单来说,就是当我们发现请求的数据即不存在与缓存,也不存在与数据库时,将空值缓存到Redis,避免频繁查询数据库。实现思路如下:

核心思路如下:

在原来的逻辑中,我们如果发现这个数据在mysql中不存在,直接就返回404了,这样是会存在缓存穿透问题的

现在的逻辑中:如果这个数据不存在,我们不会返回404 ,还是会把这个数据写入到Redis中,并且将value设置为空,欧当再次发起查询时,我们如果发现命中之后,判断这个value是否是null,如果是null,则是之前写入的数据,证明是缓存穿透数据,如果不是,则直接返回数据。


2.2 布隆过滤器

布隆过滤是一种数据统计的算法,用于检索一个元素是否存在一个集合中。

一般我们判断集合中是否存在元素,都会先把元素保存到类似于树、哈希表等数据结构中,然后利用这些结构查询效率高的特点来快速匹配判断。但是随着元素数量越来越多,这种模式对内存的占用也越来越大,检索的速度也会越来越慢。而布隆过滤的内存占用小,查询效率却很高。

此时,我们要判断元素是否存在,只需要再次基于Khash函数做运算, 得到K个角标,判断每个角标的位置是不是1:

  • 只要全是1,就证明元素存在

  • 任意位置为0,就证明元素一定不存在

假如某个元素本身并不存在,也没添加到布隆过滤器过。但是由于存在hash碰撞的可能性,这就会出现这个元素计算出的角标已经被其它元素置为1的情况。那么这个元素也会被误判为已经存在。

因此,布隆过滤器的判断存在误差:

  • 当布隆过滤器认为元素不存在时,它肯定不存在

  • 当布隆过滤器认为元素存在时,它可能存在,也可能不存在

我们可以把数据库中的数据利用布隆过滤器标记出来,当用户请求缓存未命中时,先基于布隆过滤器判断。如果不存在则直接拒绝请求,存在则去查询数据库。尽管布隆过滤存在误差,但一般都在0.01%左右,可以大大减少数据库压力。

面试题如何解决缓存穿透问题

:缓存穿透也可以说是穿透攻击,具体来说是因为请求访问到了数据库不存在的值,这样缓存无法命中,必然访问数据库。如果高并发的访问这样的接口,会给数据库带来巨大压力。

我们项目中都是基于布隆过滤器来解决缓存穿透问题的,当缓存未命中时基于布隆过滤器判断数据是否存在。如果不存在则不去访问数据库。

当然,也可以使用缓存空值的方式解决,不过这种方案比较浪费内存。


3. 缓存雪崩

面试题如何解决缓存雪崩问题

:缓存雪崩的常见原因有两个,第一是因为大量key同时过期。针对问这个题我们可以可以给缓存key设置不同的TTL值,避免key同时过期。

第二个原因是Redis宕机导致缓存不可用。针对这个问题我们可以利用集群提高Redis的可用性。也可以添加多级缓存,当Redis宕机时还有本地缓存可用。


4.缓存击穿

4.1 互斥锁

核心思路:相较于原来从缓存中查询不到数据后直接查询数据库而言,现在的方案是 进行查询之后,如果从缓存没有查询到数据,则进行互斥锁的获取,获取互斥锁后,判断是否获得到了锁,如果没有获得到,则休眠,过一会再进行尝试,直到获取到锁为止,才能进行查询。

如果获取到了锁的线程,再去进行查询,查询后将数据写入redis,再释放锁,返回数据,利用互斥锁就能保证只有一个线程去执行操作数据库的逻辑,防止缓存击穿。

操作锁的代码:

核心思路就是利用redis的setnx方法来表示获取锁,该方法含义是redis中如果没有这个key,则插入成功,返回1,在stringRedisTemplate中返回true, 如果有这个key则插入失败,则返回0,在stringRedisTemplate返回false,我们可以通过true,或者是false,来表示是否有线程成功插入key,成功插入的key的线程我们认为他就是获得到锁的线程。


private boolean tryLock(String key) {Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);
}private void unlock(String key) {stringRedisTemplate.delete(key);
}

操作代码:

 public Shop queryWithMutex(Long id)  {String key = CACHE_SHOP_KEY + id;// 1、从redis中查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get("key");// 2、判断是否存在if (StrUtil.isNotBlank(shopJson)) {// 存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//判断命中的值是否是空值if (shopJson != null) {//返回一个错误信息return null;}// 4.实现缓存重构//4.1 获取互斥锁String lockKey = "lock:shop:" + id;Shop shop = null;try {boolean isLock = tryLock(lockKey);// 4.2 判断否获取成功if(!isLock){//4.3 失败,则休眠重试Thread.sleep(50);return queryWithMutex(id);}//4.4 成功,根据id查询数据库shop = getById(id);// 5.不存在,返回错误if(shop == null){//将空值写入redisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);//返回错误信息return null;}//6.写入redisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_NULL_TTL,TimeUnit.MINUTES);}catch (Exception e){throw new RuntimeException(e);}finally {//7.释放互斥锁unlock(lockKey);}return shop;}

4.2 逻辑过期

需求:修改根据id查询商铺的业务,基于逻辑过期方式来解决缓存击穿问题

思路分析:当用户开始查询redis时,判断是否命中,如果没有命中则直接返回空数据,不查询数据库,而一旦命中后,将value取出,判断value中的过期时间是否满足,如果没有过期,则直接返回redis中的数据,如果过期,则在开启独立线程后直接返回之前的数据,独立线程去重构数据,重构完成后释放互斥锁。

private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
public Shop queryWithLogicalExpire( Long id ) {String key = CACHE_SHOP_KEY + id;// 1.从redis查询商铺缓存String json = stringRedisTemplate.opsForValue().get(key);// 2.判断是否存在if (StrUtil.isBlank(json)) {// 3.存在,直接返回return null;}// 4.命中,需要先把json反序列化为对象RedisData redisData = JSONUtil.toBean(json, RedisData.class);Shop shop = JSONUtil.toBean((JSONObject) redisData.getData(), Shop.class);LocalDateTime expireTime = redisData.getExpireTime();// 5.判断是否过期if(expireTime.isAfter(LocalDateTime.now())) {// 5.1.未过期,直接返回店铺信息return shop;}// 5.2.已过期,需要缓存重建// 6.缓存重建// 6.1.获取互斥锁String lockKey = LOCK_SHOP_KEY + id;boolean isLock = tryLock(lockKey);// 6.2.判断是否获取锁成功if (isLock){CACHE_REBUILD_EXECUTOR.submit( ()->{try{//重建缓存this.saveShop2Redis(id,20L);}catch (Exception e){throw new RuntimeException(e);}finally {unlock(lockKey);}});}// 6.4.返回过期的商铺信息return shop;
}

面试题如何解决缓存击穿问题

:缓存击穿往往是由热点Key引起的,当热点Key过期时,大量请求涌入同时查询,发现缓存未命中都会去访问数据库,导致数据库压力激增。解决这个问题的主要思路就是避免多线程并发去重建缓存,因此方案有两种。

第一种是基于互斥锁,当发现缓存未命中时需要先获取互斥锁,再重建缓存,缓存重建完成释放锁。这样就可以保证缓存重建同一时刻只会有一个线程执行。不过这种做法会导致缓存重建时性能下降严重。

第二种是基于逻辑过期,也就是不给热点Key设置过期时间,而是给数据添加一个过期时间的字段。这样热点Key就不会过期,缓存中永远有数据。

查询到数据时基于其中的过期时间判断key是否过期,如果过期开启独立新线程异步的重建缓存,而查询请求先返回旧数据即可。当然,这个过程也要加互斥锁,但由于重建缓存是异步的,而且获取锁失败也无需等待,而是返回旧数据,这样性能几乎不受影响。

需要注意的是,无论是采用哪种方式,在获取互斥锁后一定要再次判断缓存是否命中,做dubbo check. 因为当你获取锁成功时,可能是在你之前有其它线程已经重建缓存了。


文章转载自:

http://HnGB7nzB.jfjpn.cn
http://K4549sKa.jfjpn.cn
http://O9vTM3wf.jfjpn.cn
http://9kF4Hsx7.jfjpn.cn
http://ErDsH65z.jfjpn.cn
http://6MJYqOy6.jfjpn.cn
http://Kmd0UtLh.jfjpn.cn
http://RQv6B5i3.jfjpn.cn
http://pwbJymOc.jfjpn.cn
http://Dn7F3ZuV.jfjpn.cn
http://ryUUSieI.jfjpn.cn
http://rqe5gJJl.jfjpn.cn
http://gITxRDK8.jfjpn.cn
http://vNm9DTkf.jfjpn.cn
http://liVDYfhS.jfjpn.cn
http://JNpZLw3S.jfjpn.cn
http://cZKogZzY.jfjpn.cn
http://AIRVLV2j.jfjpn.cn
http://HAsMevA9.jfjpn.cn
http://mO29FlUO.jfjpn.cn
http://sFAldcrh.jfjpn.cn
http://jXfOWht3.jfjpn.cn
http://IZpOaYfo.jfjpn.cn
http://8badzPcM.jfjpn.cn
http://aT3H3Oy9.jfjpn.cn
http://GOc2697W.jfjpn.cn
http://UEzAetIt.jfjpn.cn
http://toV3mbTa.jfjpn.cn
http://SnhhyxlW.jfjpn.cn
http://QUqhylz3.jfjpn.cn
http://www.dtcms.com/wzjs/651833.html

相关文章:

  • 西宁做网站君博相约wordpress自定义后台菜单
  • 营销型网站建设的小技巧网站域名购买
  • 深圳网站建设好吗wordpress文章不能写入关键词
  • 注册网站填写不了地区WordPress 知更鸟主题
  • dz网站收款即时到账怎么做的北京网页制作设计
  • 哪个视频网站做视频赚钱什么是网站app建设
  • 考百度指数 某个关键词在某个行业网站上的淘宝客网站备案
  • 食品类网站模板地方网站域名
  • 电脑网站打不开怎么解决全国文明城市创建工作
  • 如何在各个购物网站之间做差价六安建六安建设网站
  • 南宁软件优化网站首页关键词优化公司
  • apache多网站配置企业网站前台静态模板
  • 销售网站建设公司wordpress 文章 图片 插件
  • 盐城市建设局网站打不开wordpress主题 秀
  • seo诊断工具网站新能源电动汽车哪个牌子的质量好
  • dw做网站教程视频烟台网站建站
  • 唐山手机网站建设百度极速版app下载安装
  • pe管网站建设 中企动力页面设计英文
  • 石家庄模板建站WordPress直接调用头像地址
  • 书店网站建设策划书苏州电商关键词优化
  • 厦门建设局网站工程师评审关于织金县网站建设的论文
  • 网站建设课程感想图片seo优化是什么意思
  • 如何选择网站模板一个空间能否做两个网站
  • 谷歌云 阿里云 做网站怎么建设一个网站赚钱
  • 手机自助建站永久免费linux建立网站
  • 做淘宝客网站服务器深圳市住房和建设局工程交易平台
  • 网站开发工具安卓版阿里巴巴logo高清图
  • 有没有专业做二维码连接网站在宁波seo网页怎么优化
  • 网站用户访问统计网页设计公司理念
  • 织梦网站导航固定seo计费系统登录