高考考试网
当前位置: 首页 高考资讯

redis 缓存预热和缓存雪崩(redis缓存穿透缓存击穿)

时间:2023-06-05 作者: 小编 阅读量: 3 栏目名: 高考资讯

为了克服上述的问题,项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能。redis技术就是NoSQL技术中的一种,但是引入redis又有可能出现缓存穿透,缓存击穿,缓存雪崩等问题。大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。

快,关注米兜Java,一起涨姿势~

热点推荐
  • 最全的 JVM 面试知识点(一):运行时数据区
  • Spring源码解析——创建bean
  • Spring源码解析——创建bean的实例
  • Spring,Spring MVC及Spring Boot区别
  • 求你了,再问你Java内存模型的时候别再给我讲堆栈方法区了…
Redis缓存穿透,缓存击穿,缓存雪崩原因 解决方案01前言

在我们日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者是主页访问量瞬间较大的时候,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的严重生产问题。

为了克服上述的问题,项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能。

redis技术就是NoSQL技术中的一种,但是引入redis又有可能出现缓存穿透,缓存击穿,缓存雪崩等问题。本文就对这三种问题进行较深入剖析。

02初认识
  • 缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
  • 缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
  • 缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
03缓存穿透解决方案

一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

有很多种方法可以有效地解决缓存穿透问题最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

粗暴方式伪代码:

//伪代码public object GetProductListNew() { int cacheTime = 30; String cacheKey = "product_list"; String cacheValue = CacheHelper.Get(cacheKey); if (cacheValue != null) { return cacheValue; } cacheValue = CacheHelper.Get(cacheKey); if (cacheValue != null) { return cacheValue; } else { //数据库查询不到,为空 cacheValue = GetProductListFromDB(); if (cacheValue == null) { //如果发现为空,设置个默认值,也缓存起来 cacheValue = string.Empty; } CacheHelper.Add(cacheKey, cacheValue, cacheTime); return cacheValue; }}

04缓存击穿解决方案

key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。

  • 使用互斥锁(mutex key)

业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。

SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

public String get(key) { String value = redis.get(key); if (value == null) { //代表缓存值过期 //设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置成功 value = db.get(key); redis.set(key, value, expire_secs); redis.del(key_mutex); } else { //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可 sleep(50); get(key); //重试 } } else { return value;} }

memcache代码:

if (memcache.get(key) == null) {// 3 min timeout to avoid mutex holder crashif (memcache.add(key_mutex, 3 * 60 * 1000) == true) {value = db.get(key);memcache.set(key, value);memcache.delete(key_mutex);} else {sleep(50);retry();} }

其它方案:待各位补充。

05缓存雪崩解决方案

与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key。

缓存正常从Redis中获取,示意图如下:

缓存失效瞬间示意图如下:

缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

加锁排队,伪代码如下:

//伪代码public object GetProductListNew() { int cacheTime = 30; String cacheKey = "product_list"; String lockKey = cacheKey; String cacheValue = CacheHelper.get(cacheKey); if (cacheValue != null) { return cacheValue; } else { synchronized(lockKey) { cacheValue = CacheHelper.get(cacheKey); if (cacheValue != null) { return cacheValue; } else { //这里一般是sql查询数据 cacheValue = GetProductListFromDB();CacheHelper.Add(cacheKey, cacheValue, cacheTime); } } return cacheValue; }}

加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法!

注意:加锁排队的解决方式分布式环境的并发问题,有可能还要解决分布式锁的问题;线程还会被阻塞,用户体验很差!因此,在真正的高并发场景下很少使用!

随机值伪代码:

//伪代码public object GetProductListNew() { int cacheTime = 30; String cacheKey = "product_list"; //缓存标记 String cacheSign = cacheKey"_sign"; String sign = CacheHelper.Get(cacheSign); //获取缓存值 String cacheValue = CacheHelper.Get(cacheKey); if (sign != null) { return cacheValue; //未过期,直接返回 } else { CacheHelper.Add(cacheSign, "1", cacheTime); ThreadPool.QueueUserWorkItem((arg) -> { //这里一般是 sql查询数据 cacheValue = GetProductListFromDB();//日期设缓存时间的2倍,用于脏读 CacheHelper.Add(cacheKey, cacheValue, cacheTime * 2);}); return cacheValue; }}

解释说明:

  • 缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存;
  • 缓存数据:它的过期时间比缓存标记的时间延长1倍,例:标记缓存时间30分钟,数据缓存设置为60分钟。这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存。

关于缓存崩溃的解决方法,这里提出了三种方案:使用锁或队列、设置过期标志更新缓存、为key设置不同的缓存失效时间,还有一种被称为“二级缓存”的解决方法。

06小结

针对业务系统,永远都是具体情况具体分析,没有最好,只有最合适。

于缓存其它问题,缓存满了和数据丢失等问题,大伙可自行学习。最后也提一下三个词LRU、RDB、AOF,通常我们采用LRU策略处理溢出,Redis的RDB和AOF持久化策略来保证一定情况下的数据安全。

参考相关链接:

https://blog.csdn.net/zeb_perfect/article/details/54135506

https://blog.csdn.net/fanrenxiang/article/details/80542580

https://baijiahao.baidu.com/s?id=1619572269435584821&wfr=spider&for=pc

https://blog.csdn.net/xlgen157387/article/details/79530877

END!

请留下你指尖的温度

让太阳拥抱你

记得这是一个有温度的头条号

print_r('点个好看吧!');

var_dump('点个好看吧!');

NSLog(@"点个好看吧!");

System.out.println("点个好看吧!");

console.log("点个好看吧!");

print("点个好看吧!");

printf("点个好看吧!\n");

cout << "点个好看吧!" << endl;

Console.WriteLine("点个好看吧!");

fmt.Println("点个好看吧!");

Response.Write("点个好看吧!");

alert("点个好看吧!")

echo"点个好看吧!"

    推荐阅读
  • 古装电视剧100部最好看的少年天子(少年天子因爱生恨陷入疯狂的皇后)

    福临因此提出退婚,并拟定的退婚诏书,却遭到了朝堂群臣的强烈反对。花束子随猎途中意外堕马,福临将她安排在自己的大帐中休息,博尔济吉特氏怒火中烧,想要将花束子赶走。福临怀疑博尔济吉特氏,夫妻二人同塌而卧,心里却各怀心思,福临质问博尔济吉特氏,博尔济吉特氏死不承认,两人依然不欢而散。后宫中迎来了一场选秀,郑亲王的外甥女佟腊月与鄂硕之女乌云珠同在选秀名册之上。博尔济吉特氏哭闹不止,将对福临的不满

  • 萨博9-5(saab萨博95)

    徐徐环绕的前保险杠亦把人们的视线引到了绅宝特有的蛤壳状的发动机舱盖上。排气管在保险杠内半遮半露。但aero车型却是个例外,他的椭圆型不锈钢排气管从保险杠的下部伸出,露骨地表现出性能强劲的特征。这一配置现在已成为所有新款saab系列车型中的标准配置。新型变速器还能对工作状况进行持续监控并不断满足驾驶需求。最使绅宝涡轮增压发动机的特征得到淋漓尽致发挥的是aero车型。时速达到160公里时,发动机依然表现良好。

  • 学乐云教学电脑版怎么下载(学乐云教学电脑版在哪能下载)

    下面更多详细答案一起来看看吧!学乐云教学电脑版怎么下载打开自带浏览器。输入学乐云教学电脑版并进行搜索。找到下载按钮,并将安全下载或高速下载前面的勾划掉,并点击普通下载或本地下载。下载好后会自动进入安装界面,点击安装即可。

  • 中科院研究生被同学杀害案将宣判(中科院研究生遇刺案开庭)

    案发后周凯旋很快被抓获。此次开庭,经过近四个小时的审理,于中午13时15分左右庭审结束,没有当庭宣布判决结果,法庭将另行择日宣判。图陈龙凶手周凯旋在庭审最后阶段称,自知罪孽深重,请求法庭判处其死刑立即执行。此案中,周凯旋被鉴定为“具有完全刑事责任能力”,可认定“无精神病”。随后两天,一位谢家的亲属向外界透露了周凯旋向警方交待的情况。

  • 上隐形拉链的技巧(上隐形拉链的技巧有什么)

    上隐形拉链的技巧?下面更多详细答案一起来看看吧!上隐形拉链的技巧上隐形拉链的技巧主要有以下几个方面:上隐形拉链之前,先把拉链熨烫一下,这样更平整。然后再用几个大头针,将一些拉链固定在服装上合适的位置,固定好之后开始缝制,用缝纫机缝制之前,把缝纫机换成隐形的单压脚,缝制的时候紧挨着隐形拉链的边进行缝制,缝制过程中注意不要偏离缝制轨道。

  • 妻子出轨丈夫当场被捉(妻子现场捉奸丈夫)

    事后,刘芳提起刑事自诉,请求吉首法院以侮辱罪追究李霞与她另外两名亲友的刑事责任。日前,该案开庭审理。23时许,王军与刘芳取车准备开车离开停车场,李霞与两名亲友冲上去对刘芳进行侮辱殴打,使用暴力方式强行脱掉自诉人内裤。李霞三人辩称,刘芳与李霞的丈夫有奸情,是导致本案发生的根本原因。侮辱行为不要求发生在公共场所。

  • 雨刮器喷水喷不出来是什么原因(雨刮器喷水喷的原因)

    以下内容希望对你有帮助!雨刮器喷水喷不出来是什么原因管路堵塞。正确的做法是将加注玻璃水的进水口打开,然后再去打开雨刮器喷水开关,由于这时两边都是通畅的,管子里边的空气很容易排出,空气排出后容器里的玻璃水自然就会压上来。

  • 三合一小米积木(小米积木全在这里)

    小米积木全在这里说起积木玩具,大家一定会想到乐高,确实它在世界上的影响力很高,当然其售价也非常的贵,因此让很多人望而却步再说国内小米的米兔积木系列一直备受欢迎,不仅颜值高,设计新颖,而且价格还非常的亲民,所以很多人选。

  • 左转红灯过了线停车算闯红灯吗(你知道吗)

    左转红灯过了线停车算闯红灯吗超过停车线车辆没有再移动不算闯红灯。在未设置非机动车信号灯和人行横道信号灯的路口,非机动车和行人应当按照机动车信号灯的表示通行。红灯亮时,右转弯的车辆在不妨碍被放行的车辆、行人通行的情况下,可以通行。

  • 车主避让救护车违反交通规则要处罚吗

    车主避让救护车违反交通规则不会被处罚,在行驶中应当主动避让执行医疗急救任务的救护车,因避让违反道路交通安全法律、法规的,免予行政处罚。但是不及时避让救护车的,会得到相应的处罚。阻碍人民警察依法执行职务的,从重处罚。