目录
前言
最近在学习B站上的视频:《黑马程序员Redis入门到实战教程》,本文的图片均来自该网课,具体内容由我学习消化后所写,作为一个学习笔记的存在吧,主要用于我日后复习,也可以供喜欢看文章 / 没时间看视频的小伙伴们参考,这也是我第一次写博客,有问题欢迎指出,共同学习,共同进步!
一、缓存穿透
1.1 概念
首先,我们先快速过一遍,在利用Redis缓存的情况下,客户端请求的流程,即客户端的请求先到缓存中查询,若找到,则返回给前端,若未找到,则进入数据库查询,若在数据库中找到,则将其存入缓存,并把数据返回给前端,若在数据库中未找到,则证明客户端的请求有问题。
于是,当客户端请求的数据在缓存和数据库中都未找到时,就会引出缓存穿透的问题。
简单来说,缓存穿透就是指客户端的请求永远都是直接穿透缓存,直击数据库。
为什么会发生这种情况呢?就是因为客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。
所以,当有大量的请求同时打到数据库时,一定会对性能造成非常严重的打击(也许有人会想为什么客户端的请求会在缓存和数据库中都找不到,这块我也不太清楚,我能想到的就是例如有人恶意攻击,利用不存在的id进行查询等等)
1.2 缓存穿透解决方案
常见的解决方案有两种:缓存空对象 和 布隆过滤
解决方案一:缓存空对象
先上图:

缓存空对象的原理很简单:你每次查询缓存都找不到,然后就来查询我数据库,我数据库也压根没有,于是每次都来查询我数据库,给我造成很大压力,那我直接存储一个空对象到缓存,你下次来查,就直接从缓存中查到这个空对象了,于是就避免了你再到我数据库这里来。
Redis能承载的并发要比数据库高很多,数据库返回一个空对象存到缓存中,之后大量的请求再打过来就会被缓存给打发了,不会再进入到数据库,也就避免了频繁查询数据库导致性能缺失。
| 缓存空对象 | |
| 优点 | 实现简单,维护方便 |
| 缺点 | 额外的内存消耗 可能造成短期的不一致 |
由此可见,该方法的优点是:实现简单,维护方便
但也有相应缺点:
额外的内存消耗
因为保存了一个空对象在Redis中,所以可能会对其造成额外的内存消耗,但这个方法也可以通过给空对象设置过期时间来缓解。
例如请求端突然大量查询 id为 0 的用户信息,缓存和数据库都没有,于是数据库存储一个空对象在缓存中,并设置时间为2分钟,假设2分钟后请求端不再进行查询,空对象一到时间也会自动销毁,避免占内存。
可能造成短期的不一致
假设请求端查询 id 为 0 的用户信息,缓存和数据库都没有,于是数据库存储一个空对象在缓存中,结果这时候数据库真的又插入一条 id 为 0 的用户信息,那这时前端请求从缓存拿到的数据和数据库中的数据就不一致了。
其实这个问题也可以通过给空对象设置过期时间来缓解,设置一个合适的时间,时间一到,自动销毁,下次来查就能更新一致了,如果实在不放心,也可以主动更新,数据库一旦有改,手动将缓存中数据更新。
解决方案二:布隆过滤

简单来说,布隆过滤就是在Redis前加一个布隆过滤器,前端请求过来先由过滤器拦截,过滤器查询数据库中是否有数据,如果有,则放行,在缓存中查询,查到,则返回,没查到,也不要紧,布隆过滤的时候已经确定了数据库中有数据,直接查数据库;而如果布隆过滤器查询到数据库中并没有数据,则直接返回,避免了请求全部打到数据库的情况。
于是问题来了:布隆过滤器怎么查询数据库有没有数据的?这个过程不浪费时间吗?这个查询准确吗?
(这里我学的还不够深入,所以只能做简单概述,大家可以另找地方学习布隆过滤原理,我之后学习完也会更新)
布隆过滤器的原理,简单来说就是把数据库的数据通过哈希思想进行处理,弄成一个庞大的二进制数组存储在布隆过滤器中,根据该数组通过哈希思想来判断当前请求数据是否在数据库中,因为是以二进制数组形式存储,内存也不会占太大,但是要记住一点:说不存在一定不存在,说存在不一定存在,即布隆过滤有误判的可能(原因是只要以哈希思想处理数据,就可能会发生哈希冲突,所以就可能会发生误判)
| 布隆过滤 | |
| 优点 | 内存占用较少,没有多余key |
| 缺点 | 实现复杂 存在误判可能 |
1.3 其他的一些解决方案
1、增强id的复杂度,避免被猜测id规律
主要是为了避免有人恶意攻击,大量访问不存在的id导致缓存穿透,相当于直接预防问题发生,而不是当问题发生后再想解决方案。后面的2、3、4方法其实都是思想。
2、做好数据的基础格式校验
3、加强用户权限校验
4、做好热点参数的限流
做好限流,即使有大量请求来袭,也不至于让它们同时涌进来造成拥堵,这个技术方法应该涉及到Springcloud方面的知识,我还没学到,不太了解。
二、缓存雪崩
2.1 概念
先看这张图:

缓存雪崩顾名思义,指Redis缓存在一瞬间就像雪崩一样垮了,于是大量的请求瞬间跑到数据库来,造成性能的缺失。
造成这种情况的原因一般是 同一时段大量的缓存key同时失效 或者 Redis服务宕机,从而导致大量请求到达数据库,带来巨大压力。
缓存穿透与缓存雪崩的区别:
主要就是造成原因的不同,穿透是因为访问了不存在的数据,所以每次在缓存查不到,就跑到数据库查,然后一直重复这个过程,如果有大量同样的请求,频繁访问数据库就会搞垮性能;
而雪崩就像一堆人站在舞台上,结果舞台跨了,即大量请求同时访问数据库,必然搞垮性能。
2.2 缓存雪崩解决方案
1、给不同的Key的TTL添加随机值
假设Redis服务没有宕机的情况下,为什么会发生大量缓存数据同时失效?就是因为他们同时过期了,那我尽量不要把数据的过期时间设置成一样的,让它们错峰过期,这样不就避免了缓存雪崩的问题吗?确实是的,不过长久来看,我个人认为这个方法比较一般,怎么安排不同数据的过期时间?当数据真的超级多的时候怎么安排?如果是Redis宕机了那这个方法也根本救不了。
2、利用Redis集群提高服务的可用性
集群,即多搞几个Redis,设置主从,同步数据,可以再搞一个哨兵监控状态,假设一个崩了另一个就补上,可以很好地实现Redis的高可用性。
3、给缓存业务添加降级限流策略
服务降级,比如服务器崩了,Redis崩了,这个时候可以赶紧做服务降级,对请求直接拒绝服务,而不是把请求继续压在数据库上,从而保护数据库;限流方法上面也提过,相当于预防问题发生,降级限流这样一块应该都是Springcloud微服务方面的知识。
4、给业务添加多级缓存
顾名思义,可以在浏览器搞缓存(当然只能缓存一些静态数据,动态数据没办法),可以在反向代理服务器nginx上搞缓存,jvm内部搞本地缓存等等,相当于多穿几件防弹衣,一件打破了还能剩几件。
总结
缓存穿透就是缓存和数据库压根没有数据,所以请求每次都直接穿透缓存打到数据库,就像一根烤串那样,直接穿透,常见解决方案有 存储空值到Redis中、布隆过滤;
缓存雪崩就是一堆数据同时过期 或者 Redis宕机 ,就像一堆人站在那种玻璃栈道上,然后玻璃碎了,全掉下去(有点惊悚),常见解决方案有 集群、降级限流、多级缓存;
还剩一个缓存击穿没说,放到下一篇文章,正在更新中。。。
&spm=1001.2101.3001.5002&articleId=146027958&d=1&t=3&u=f435e284f18741a5a7c6eaa3c95c6317)
1182

被折叠的 条评论
为什么被折叠?



