快速搞懂 Redis 缓存穿透、缓存雪崩、缓存击穿(一)

目录

前言

一、缓存穿透

1.1  概念

1.2  缓存穿透解决方案

解决方案一:缓存空对象

解决方案二:布隆过滤

1.3 其他的一些解决方案

二、缓存雪崩

2.1 概念

2.2  缓存雪崩解决方案

总结


前言

最近在学习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宕机 ,就像一堆人站在那种玻璃栈道上,然后玻璃碎了,全掉下去(有点惊悚),常见解决方案有 集群、降级限流、多级缓存;

还剩一个缓存击穿没说,放到下一篇文章,正在更新中。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值