精华内容
下载资源
问答
  • 缓存雪崩
    千次阅读
    2022-02-08 18:35:46

    缓存雪崩

    大量的应用请求无法在Redis缓存中进行处理,紧接着应用将大量请求发送到数据库层,导致数据库层的压力激增

    缓存雪崩一般有两个原因导致,解决方案也有所不同

    出现原因一

    缓存中有大量Key同时过期,导致大量请求无法得到处理,大量数据需要回源数据库

    解决方案

    方案一 差异化设置过期时间

    差异化缓存过期时间,不要让大量的 Key 在同一时间过期。比如,在初始化缓存的时候,给这些数据的过期时间增加一个较小的随机数,这样一来不同数据的过期时间有所差别又差别不大,即避免了大量数据同时过期又能保证这些数据在相近的时间失效

    方案二 服务降级

    允许核心业务访问数据库,非核心业务直接返回预定义的信息

    方案三 不设置过期时间

    初始化缓存数据的时候设置缓存永不过期,然后启动一个后台线程 30 秒一次定时把所有数据更新到缓存,而且通过适当的休眠,控制从数据库更新数据的频率,降低数据库压力。

    出现原因二

    Redis实例发生故障宕机,无法处理请求,就会导致大量请求积压到数据库层

    解决方案

    方案一 服务熔断

    暂停业务应用对缓存服务的访问,从而降低对数据库的压力

    方案二 请求限流

    控制每秒进入应用程序的请求数,避免过多的请求被发到数据库

    方案三 Redis构建高可靠集群

    通过主从节点的方式构建Redis高可靠集群。可以保证在Redis主节点故障宕机时,从节点切换到主节点,继续提供服务,避免由于缓存实例宕机导致缓存雪崩

    缓存击穿

    热点数据在某一时刻过期了,可能会导致随之而来的大量的并发请求直接打到数据库,导致数据库压力激增。

    解决方案

    方案一 分布式锁

    采用锁机制控制打到数据库的请求,读取数据后将其写回到缓存,保证了其他线程可以命中缓存。

    //伪代码
    加锁成功;
    result=redis.getKey(X);
    if(result==null){
      result=db.getData(X);
      redis.setData(X,result);
    }
    释放锁;
    
    方案二 热点数据不设置过期时间

    缓存穿透

    客户端 请求了一个业务程序中不存在的数据,即要访问的数据既不在Redis缓存中,也不在数据库中。导致每次类似的请求,都会先从Redis–>数据库去查数据,最终也无果。

    当存在大量请求这样访问时,会同时给缓存和数据库带来很大压力。

    出现原因

    1、误操作导致:缓存中的数据和数据库中的数据都被误删了

    2、恶意攻击:专门访问数据库中不存在的数据

    解决方案

    方案一 设置缺省值

    比如当请求id=1000的用户数据时,在数据库中找不到该条数据,则将NONE这样具有特殊含义的字符串设置到缓存中,后续客户端再请求该数据时,可以直接命中缓存,不再访问数据库。

    但是这样有个问题,如果客户端访问大量的不同的数据,那这些大量无效的数据可能会占满缓存

    方案二 使用布隆过滤器过滤数据

    布隆过滤器由一个初值都为 0 的 bit 数组和 N 个哈希函数组成,可以用来快速判断某个数据是否存在。

    工作原理

    1、使用 N 个哈希函数,分别计算这个数据的哈希值,得到 N 个哈希值

    2、把这 N 个哈希值对 bit 数组的长度取模,得到每个哈希值在数组中的对应位置。

    3、标记数据,把对应位置的 bit 位设置为 1

    如果数据不存在,那布隆过滤器中bit数组对应的bit位的值为0.

    过滤规则

    当一个元素需要被检索时,使用N个哈希函数对该元素求得哈希值,并定位到bit数组中。如果发现对应位置处bit位有任何一个0,就说明这个元素不存在于布隆过滤器;当bit位都是1,说明这个元素可能存在于布隆过滤器(这里说可能,是因为不同元素经过哈希运算可能得到相同的哈希值)

    像Guava、Redisson 都有布隆过滤器的实现。

    我们只需要初始化布隆过滤器,即将数据添加到布隆过滤器中。然后借助布隆过滤器去判断元素是否存在

    参考文献
    Redis核心技术与实战

    更多相关内容
  • 面试中缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级怎么解答 面试中缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级怎么解答 面试中缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级怎么解答
  • 什么是缓存雪崩、击穿、穿透?

    万次阅读 多人点赞 2022-03-13 17:55:28
    什么是缓存雪崩、击穿、穿透? 用户的数据一般都是存储于数据库,数据库的数据是落在磁盘上的,磁盘的读写速度可以说是计算机里最慢的硬件了。 当用户的请求,都访问数据库的话,请求数量一上来,数据库很容易就奔溃...

    什么是缓存雪崩、击穿、穿透?

    用户的数据一般都是存储于数据库,数据库的数据是落在磁盘上的,磁盘的读写速度可以说是计算机里最慢的硬件了。

    当用户的请求,都访问数据库的话,请求数量一上来,数据库很容易就奔溃的了,所以为了避免用户直接访问数据库,会用 Redis 作为缓存层。

    因为 Redis 是内存数据库,我们可以将数据库的数据缓存在 Redis 里,相当于数据缓存在内存,内存的读写速度比硬盘快好几个数量级,这样大大提高了系统性能。

    图片

    引入了缓存层,就会有缓存异常的三个问题,分别是缓存雪崩、缓存击穿、缓存穿透

    这三个问题也是面试中很常考察的问题,我们不光要清楚地知道它们是怎么发生,还需要知道如何解决它们。

    话不多说,发车!

    图片


    缓存雪崩

    通常我们为了保证缓存中的数据与数据库中的数据一致性,会给 Redis 里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到 Redis 里,这样后续请求都可以直接命中缓存。

    图片

    那么,当大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。

    图片

    可以看到,发生缓存雪崩有两个原因:

    • 大量数据同时过期;
    • Redis 故障宕机;

    不同的诱因,应对的策略也会不同。

    大量数据同时过期

    针对大量数据同时过期而引发的缓存雪崩问题,常见的应对方法有下面这几种:

    • 均匀设置过期时间;
    • 互斥锁;
    • 双 key 策略;
    • 后台更新缓存;

    1. 均匀设置过期时间

    如果要给缓存数据设置过期时间,应该避免将大量的数据设置成同一个过期时间。我们可以在对缓存数据设置过期时间时,给这些数据的过期时间加上一个随机数,这样就保证数据不会在同一时间过期。

    2. 互斥锁

    当业务线程在处理用户请求时,如果发现访问的数据不在 Redis 里,就加个互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到 Redis 里),当缓存构建完成后,再释放锁。未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

    实现互斥锁的时候,最好设置超时时间,不然第一个请求拿到了锁,然后这个请求发生了某种意外而一直阻塞,一直不释放锁,这时其他请求也一直拿不到锁,整个系统就会出现无响应的现象。

    3. 双 key 策略

    我们对缓存数据可以使用两个 key,一个是主 key,会设置过期时间,一个是备 key,不会设置过期,它们只是 key 不一样,但是 value 值是一样的,相当于给缓存数据做了个副本。

    当业务线程访问不到「主 key 」的缓存数据时,就直接返回「备 key 」的缓存数据,然后在更新缓存的时候,同时更新「主 key 」和「备 key 」的数据。

    4. 后台更新缓存

    业务线程不再负责更新缓存,缓存也不设置有效期,而是让缓存“永久有效”,并将更新缓存的工作交由后台线程定时更新

    事实上,缓存数据不设置有效期,并不是意味着数据一直能在内存里,因为当系统内存紧张的时候,有些缓存数据会被“淘汰”,而在缓存被“淘汰”到下一次后台定时更新缓存的这段时间内,业务线程读取缓存失败就返回空值,业务的视角就以为是数据丢失了。

    解决上面的问题的方式有两种。

    第一种方式,后台线程不仅负责定时更新缓存,而且也负责频繁地检测缓存是否有效,检测到缓存失效了,原因可能是系统紧张而被淘汰的,于是就要马上从数据库读取数据,并更新到缓存。

    这种方式的检测时间间隔不能太长,太长也导致用户获取的数据是一个空值而不是真正的数据,所以检测的间隔最好是毫秒级的,但是总归是有个间隔时间,用户体验一般。

    第二种方式,在业务线程发现缓存数据失效后(缓存数据被淘汰),通过消息队列发送一条消息通知后台线程更新缓存,后台线程收到消息后,在更新缓存前可以判断缓存是否存在,存在就不执行更新缓存操作;不存在就读取数据库数据,并将数据加载到缓存。这种方式相比第一种方式缓存的更新会更及时,用户体验也比较好。

    在业务刚上线的时候,我们最好提前把数据缓起来,而不是等待用户访问才来触发缓存构建,这就是所谓的缓存预热,后台更新缓存的机制刚好也适合干这个事情。

    Redis 故障宕机

    针对 Redis 故障宕机而引发的缓存雪崩问题,常见的应对方法有下面这几种:

    • 服务熔断或请求限流机制;
    • 构建 Redis 缓存高可靠集群;

    1. 服务熔断或请求限流机制

    因为 Redis 故障宕机而导致缓存雪崩问题时,我们可以启动服务熔断机制,暂停业务应用对缓存服务的访问,直接返回错误,不用再继续访问数据库,从而降低对数据库的访问压力,保证数据库系统的正常运行,然后等到 Redis 恢复正常后,再允许业务应用访问缓存服务。

    服务熔断机制是保护数据库的正常允许,但是暂停了业务应用访问缓存服系统,全部业务都无法正常工作

    为了减少对业务的影响,我们可以启用请求限流机制,只将少部分请求发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到 Redis 恢复正常并把缓存预热完后,再解除请求限流的机制。

    2. 构建 Redis 缓存高可靠集群

    服务熔断或请求限流机制是缓存雪崩发生后的应对方案,我们最好通过主从节点的方式构建 Redis 缓存高可靠集群

    如果 Redis 缓存的主节点故障宕机,从节点可以切换成为主节点,继续提供缓存服务,避免了由于 Redis 故障宕机而导致的缓存雪崩问题。


    缓存击穿

    我们的业务通常会有几个数据会被频繁地访问,比如秒杀活动,这类被频地访问的数据被称为热点数据。

    如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。

    图片

    可以发现缓存击穿跟缓存雪崩很相似,你可以认为缓存击穿是缓存雪崩的一个子集。

    应对缓存击穿可以采取前面说到两种方案:

    • 互斥锁方案,保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
    • 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;

    缓存穿透

    当发生缓存雪崩或击穿时,数据库中还是保存了应用要访问的数据,一旦缓存恢复相对应的数据,就可以减轻数据库的压力,而缓存穿透就不一样了。

    当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。

    图片

    缓存穿透的发生一般有这两种情况:

    • 业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据;
    • 黑客恶意攻击,故意大量访问某些读取不存在数据的业务;

    应对缓存穿透的方案,常见的方案有三种。

    • 第一种方案,非法请求的限制;
    • 第二种方案,缓存空值或者默认值;
    • 第三种方案,使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在;

    第一种方案,非法请求的限制

    当有大量恶意请求访问不存在的数据的时候,也会发生缓存穿透,因此在 API 入口处我们要判断求请求参数是否合理,请求参数是否含有非法值、请求字段是否存在,如果判断出是恶意请求就直接返回错误,避免进一步访问缓存和数据库。

    第二种方案,缓存空值或者默认值

    当我们线上业务发现缓存穿透的现象时,可以针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用,而不会继续查询数据库。

    第三种方案,使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在。

    我们可以在写入数据库数据时,使用布隆过滤器做个标记,然后在用户请求到来时,业务线程确认缓存失效后,可以通过查询布隆过滤器快速判断数据是否存在,如果不存在,就不用通过查询数据库来判断数据是否存在。

    即使发生了缓存穿透,大量请求只会查询 Redis 和布隆过滤器,而不会查询数据库,保证了数据库能正常运行,Redis 自身也是支持布隆过滤器的。

    那问题来了,布隆过滤器是如何工作的呢?接下来,我介绍下。

    布隆过滤器由「初始值都为 0 的位图数组」和「 N 个哈希函数」两部分组成。当我们在写入数据库数据时,在布隆过滤器里做个标记,这样下次查询数据是否在数据库时,只需要查询布隆过滤器,如果查询到数据没有被标记,说明不在数据库中。

    布隆过滤器会通过 3 个操作完成标记:

    • 第一步,使用 N 个哈希函数分别对数据做哈希计算,得到 N 个哈希值;
    • 第二步,将第一步得到的 N 个哈希值对位图数组的长度取模,得到每个哈希值在位图数组的对应位置。
    • 第三步,将每个哈希值在位图数组的对应位置的值设置为 1;

    举个例子,假设有一个位图数组长度为 8,哈希函数 3 个的布隆过滤器。

    图片

    在数据库写入数据 x 后,把数据 x 标记在布隆过滤器时,数据 x 会被 3 个哈希函数分别计算出 3 个哈希值,然后在对这 3 个哈希值对 8 取模,假设取模的结果为 1、4、6,然后把位图数组的第 1、4、6 位置的值设置为 1。当应用要查询数据 x 是否数据库时,通过布隆过滤器只要查到位图数组的第 1、4、6 位置的值是否全为 1,只要有一个为 0,就认为数据 x 不在数据库中

    布隆过滤器由于是基于哈希函数实现查找的,高效查找的同时存在哈希冲突的可能性,比如数据 x 和数据 y 可能都落在第 1、4、6 位置,而事实上,可能数据库中并不存在数据 y,存在误判的情况。

    所以,查询布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据


    总结

    缓存异常会面临的三个问题:缓存雪崩、击穿和穿透。

    其中,缓存雪崩和缓存击穿主要原因是数据不在缓存中,而导致大量请求访问了数据库,数据库压力骤增,容易引发一系列连锁反应,导致系统奔溃。不过,一旦数据被重新加载回缓存,应用又可以从缓存快速读取数据,不再继续访问数据库,数据库的压力也会瞬间降下来。因此,缓存雪崩和缓存击穿应对的方案比较类似。

    而缓存穿透主要原因是数据既不在缓存也不在数据库中。因此,缓存穿透与缓存雪崩、击穿应对的方案不太一样。

    我这里整理了表格,你可以从下面这张表格很好的知道缓存雪崩、击穿和穿透的区别以及应对方案。

    图片


    参考资料:

    1.《极客时间:Redis核心技术与实战》

    1. https://github.com/doocs/advanced-java/blob/main/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md

    2. https://medium.com/@mena.meseha/3-major-problems-and-solutions-in-the-cache-world-155ecae41d4f

    展开全文
  • 在现代软件架构中,缓存的应用已经非常普及。缓存的使用在面试和实践中都是避不开的硬技能、硬知识,如果你说还不太熟悉缓存的使用,可能都不好意思说自己是程序员。 当我们使用缓存时,目标通常有两个:第一,提升...

    背景

    在现代软件架构中,缓存的应用已经非常普及。缓存的使用在面试和实践中都是避不开的硬技能、硬知识,如果你说还不太熟悉缓存的使用,可能都不好意思说自己是程序员。

    这篇文章,带大家进一步学习在缓存使用中不得不考虑三个特殊场景:缓存穿透、缓存雪崩、缓存击穿。

    为什么说不得不考虑?因为如果不考虑这些特殊的场景,在高并发的情况可能直接导致系统崩溃。下面以常见的Redis缓存组件为例来讲解这三种场景及解决方案。

    大前提

    当我们使用缓存时,目标通常有两个:第一,提升响应效率和并发量;第二,减轻数据库的压力。

    而本文中所提到的这三种场景:缓存穿透、缓存雪崩和缓存击穿的发生,都是因为在某些特殊情况下,缓存失去了预期的功能所致。

    当缓存失效或没有抵挡住流量,流量直接涌入到数据库,在高并发的情况下,可能直接击垮数据库,导致整个系统崩溃。

    这就是我们需要知道的大前提,而缓存穿透、缓存雪崩和缓存击穿,只不过是在这个大前提下的不同场景的细分场景而已。

    缓存穿透

    大多数情况,缓存可以减少数据库的查询,提升系统性能。

    通常流程是:一个请求过来,先查询是否在缓存当中,如果缓存中存在,则直接返回。如果缓存中不存在对应的数据,则检索数据库,如果数据库中存在对应的数据,则更新缓存并返回结果。如果数据库中也不存在对应的数据,则返回空或错误。

    缓存穿透(cache penetration)是用户访问的数据既不在缓存当中,也不在数据库中。出于容错的考虑,如果从底层数据库查询不到数据,则不写入缓存。这就导致每次请求都会到底层数据库进行查询,缓存也失去了意义。当高并发或有人利用不存在的Key频繁攻击时,数据库的压力骤增,甚至崩溃,这就是缓存穿透问题。

    缓存穿透

    缓存穿透发生的场景一般有两类:

    • 原来数据是存在的,但由于某些原因(误删除、主动清理等)在缓存和数据库层面被删除了,但前端或前置的应用程序依旧保有这些数据;

    • 恶意攻击行为,利用不存在的Key或者恶意尝试导致产生大量不存在的业务数据请求。

    缓存穿透通常有四种解决方案,我们逐一介绍分析。

    方案一:缓存空值(null)或默认值

    分析业务请求,如果是正常业务请求时发生缓存穿透现象,可针对相应的业务数据,在数据库查询不存在时,将其缓存为空值(null)或默认值。需要注意的是,针对空值的缓存失效时间不宜过长,一般设置为5分钟之内。当数据库被写入或更新该key的新数据时,缓存必须同时被刷新,避免数据不一致。

    方案二:业务逻辑前置校验

    在业务请求的入口处进行数据合法性校验,检查请求参数是否合理、是否包含非法值、是否恶意请求等,提前有效阻断非法请求。比如,根据年龄查询时,请求的年龄为-10岁,这显然是不合法的请求参数,直接在参数校验时进行判断返回。

    方案三:使用布隆过滤器请求白名单

    在写入数据时,使用布隆过滤器进行标记(相当于设置白名单),业务请求发现缓存中无对应数据时,可先通过查询布隆过滤器判断数据是否在白名单内,如果不在白名单内,则直接返回空或失败。

    方案四:用户黑名单限制

    当发生异常情况时,实时监控访问的对象和数据,分析用户行为,针对故意请求、爬虫或攻击者,进行特定用户的限制;

    当然,可能针对缓存穿透的情况,也有可能是其他的原因引起,可以针对具体情况,采用对应的措施。

    缓存雪崩

    在使用缓存时,通常会对缓存设置过期时间,一方面目的是保持缓存与数据库数据的一致性,另一方面是减少冷缓存占用过多的内存空间。

    但当缓存中大量热点缓存采用了相同的实效时间,就会导致缓存在某一个时刻同时实效,请求全部转发到数据库,从而导致数据库压力骤增,甚至宕机。从而形成一系列的连锁反应,造成系统崩溃等情况,这就是缓存雪崩(Cache Avalanche)。

    缓存雪崩

    上面讲到的是热点key同时失效的场景,另外就是由于某些原因导致缓存服务宕机、挂掉或不响应,也同样会导致流量直接转移到数据库。

    所以,缓存雪崩的场景通常有两个:

    • 大量热点key同时过期;

    • 缓存服务故障;

    缓存雪崩的解决方案:

    • 通常的解决方案是将key的过期时间后面加上一个随机数(比如随机1-5分钟),让key均匀的失效。

    • 考虑用队列或者锁的方式,保证缓存单线程写,但这种方案可能会影响并发量。

    • 热点数据可以考虑不失效,后台异步更新缓存,适用于不严格要求缓存一致性的场景。

    • 双key策略,主key设置过期时间,备key不设置过期时间,当主key失效时,直接返回备key值。

    • 构建缓存高可用集群(针对缓存服务故障情况)。

    • 当缓存雪崩发生时,服务熔断、限流、降级等措施保障。

    缓存击穿

    缓存雪崩是指只大量热点key同时失效的情况,如果是单个热点key,在不停的扛着大并发,在这个key失效的瞬间,持续的大并发请求就会击破缓存,直接请求到数据库,好像蛮力击穿一样。这种情况就是缓存击穿(Cache Breakdown)。

    缓存击穿

    从定义上可以看出,缓存击穿和缓存雪崩很类似,只不过是缓存击穿是一个热点key失效,而缓存雪崩是大量热点key失效。因此,可以将缓存击穿看作是缓存雪崩的一个子集。

    缓存击穿的解决方案:

    • 使用互斥锁(Mutex Key),只让一个线程构建缓存,其他线程等待构建缓存执行完毕,重新从缓存中获取数据。单机通过synchronized或lock来处理,分布式环境采用分布式锁。

    • 热点数据不设置过期时间,后台异步更新缓存,适用于不严格要求缓存一致性的场景。

    • ”提前“使用互斥锁(Mutex Key):在value内部设置一个比缓存(Redis)过期时间短的过期时间标识,当异步线程发现该值快过期时,马上延长内置的这个时间,并重新从数据库加载数据,设置到缓存中去。

    小结

    本文介绍了在使用缓存时经常会遇到的三种异常情况:缓存穿透、缓存雪崩和缓存击穿。

    三种异常情况从根本上来说都是因为本应该访问缓存的,但是缓存不存在或服务异常,导致流量直接进入了数据库层面。

    其中缓存雪崩和缓存击穿是因为数据不存在(或服务异常获取不到),导致大量请求访问数据库,从而导致数据库压力骤增,甚至崩溃。

    而缓存穿透则是由于数据本身就不存在,导致缓存没有进行数据缓存,流量进入数据库层。

    针对不同的缓存异常场景,可选择不同的方案来进行处理。当然,除了上述方案,我们还可以限流、降级、熔断等服务层的措施,也可以考虑数据库层是否可以进行横向扩展,当缓存异常发生时,确保数据库能够抗住流量,不至于让整个系统崩溃。

    展开全文
  • 二、缓存穿透,缓存击穿和缓存雪崩 缓存穿透 描述:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1024”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致...
  • 缓存系列:缓存雪崩的解决思路

    千次阅读 2022-03-24 22:51:18
    缓存,已经是一个老生常谈的技术了,在高并发读的情况下对于读服务来说可谓是抗流量的银弹。 今天我们就来谈谈:缓存雪崩

    大家好,我是李哥。

    上次我们讨论了在分布式系统下的缓存架构体系,从浏览器缓存到客户端缓存,再到CDN缓存,再到反向代理缓存,再到本地缓存,再到分布式缓存。整个链路中有非常多的缓存。

    在整个缓存链路,存在各种各样的问题,常见的问题有缓存穿透、缓存击穿、缓存雪崩、缓存数据一致性问题等。不常见的问题有缓存倾斜、缓存阻塞、缓存慢查询、缓存主从一致性问题、缓存高可用、缓存故障发现与故障恢复、集群扩容收缩、大Key热Key等等。

    今天我们就来聊聊:缓存雪崩

    缓存雪崩,顾名思义,是缓存崩了。如果这样理解的话,那就错了,请跟我来一探究竟吧。

    老规矩,先看一下本文大纲:

    什么是缓存雪崩

    我们知道,缓存的工作原理是先从缓存中获取数据,如果有数据则直接返回给用户,如果没有数据则从慢速设备上读取实际数据并且将数据放入缓存。就像这样:

    缓存里面的数据有很多,如果有一个key过期,那么就需要回溯查询,如果这个key是热点key,慢设备压力剧增,有可能导致慢设备宕机。就像这样:

    这便是我们之前说的:缓存击穿(缓存系列:缓存击穿的解决思路_laohei_java的博客-CSDN博客

    那如果是很多key都过期了,那请求都会透过缓存层,直奔慢设备了,如果这些失效的key的请求之和很大,那么慢设备压力剧增,有可能导致慢设备宕机。就像这样:

    这便是我们今天的主题:缓存雪崩

    没错,从上面的含义其实已经能够理解出一个区别: 缓存击穿强调单Key过期+高并发; 缓存雪崩强调多key过期+高并发

    (所以,缓存雪崩不是缓存崩了,是一大片大片的缓存数据都在同一时间都失效了)

    雪崩,实在是太可怕了。

    缓存雪崩的痛点有哪些

    1. 热点数据扎堆过期

    2. 缓存层瞬间透明化

    3. 慢设备层有被击垮的风险

    大家猜想一下,为什么会瞬间有大量数据过期呢?

    有两个方向,其一是大量数据同时放入缓存+过期时间设置的时间是一致的;其二是大量数据放入缓存的时间点不一样,但是过期时间是同一时间过期。

    其一比较好理解,给大家举几个场景就更好了理解了,比如系统在启动的时候或者每天定时的对大量数据进行预热,并且过期时间是一样的。又或者是大促,商品在同一时刻开放,大量的用户进行不同商品的访问,这些商品数据几乎同时进入缓存,并且过期时间是一样的。

    其二不太容易理解,给大家举个场景就好了。比如有一个给用户推送消息的需求,但是一天只允许推送一次,假设给张三同学早上8点推送,那么可以将这条数据放入缓存,过期时间为16小时,再次给张三推送的时候检查缓存是否存在,缓存存在则不允许推送了,缓存不存在则允许推送。给李四同学下午14点推送了一条消息,那么给李四同学放缓存的数据过期时间应该是10小时。这个场景就解释了在不同的时间点放入的数据,它们的过期时间不一样,但是都是在同一时刻过期(在这个例子中是每天0点过期)。

    缓存雪崩的解决思路

    1、从上述的其一来看,是数据放入缓存的时间和过期时间一样,所以最终大量数据同一时间过期。

    所以,我们从这一点来看,我们可以改变数据放入缓存的的时间,也可以选择修改数据的过期时间,让过期时间不一致,最终的目的是让数据分散在不同的时间点过期,从而减少数据库的高并发压力。很显然,修改数据的过期时间更简单一些,让缓存时间在一定的区域随机取值,很轻松就能解决了一个缓存雪崩的问题。

    2、当然了,问题的产生是数据过期了,所以还有一种解决方案是:让你的数据永不过期!显然,你的leader或者身为leader的你是不会这么玩的,这个方案基本不可行。原因是就算让缓存数据在缓存永不过期,那难道缓存敢保证100%保证可用吗?不敢,所以,你还是需要准备planB,做好缓存宕机或者缓存数据不存在的备案。

    3、既然是因为并发访问导致,我们是不是可以由高并发转换低并发,称之为互斥锁,或者分布式锁等,总之,加锁来保证高并发转换成低并发。

    4、我们继续分析,像这种热点数据,是不是应该由热点服务器去完成,对吧?我们应该去做隔离机制,如果你有一套实时热点发现系统,再加上热点流量自动迁移到热点服务器,就算有这些有什么用,能解决问题吗?答案是不能,因为热点服务器仍然是需要防止缓存雪崩的,方案在上面已经提到过了就不再赘述了。这里只是抛砖引玉,浅谈环境隔离与实时热点发现。

    5、继续,既然是数据库承受不住了,我们在知道问题的情况下,可以对数据做离散分布,让它均匀地分布在我们的分布式数据库中,同时对数据库尽量的水平扩容,常见的分库分表策略有32库32表,64库64表,128库128表......,这样做的目的是让单台数据库压力变小,从而防止缓存雪崩。

    6、继续分析,我们从现象来看,是数据库宕机了,原因是数据库接受到的瞬间请求太多了,数据库扛不住压力所以就停止工作了。那我们是不是可以这么分析,如果我们提前知道数据库能承受的最大阈值是多少,并且提前设置好数据库的阈值或者服务的阈值,如果瞬间流量来了,我们把超过阈值的流量进行排队等待或者直接拒绝服务,保证数据库的压力是不超过阈值的,是不是也能解决缓存雪崩所带来的影响呢?

    那么这里面有涉及到几个数据:数据库的阈值从何得知、服务的阈值从何得知、如何设置数据库或者服务的阈值。

    答案是:数据的阈值应该是压测后得出,而设置阈值应该是在网关层进行限流处理,所以你需要有这样的限流平台。

    对于压测和网关,我们后续会有专门的文章来讨论,本期暂且不深入了,敬请期待。 可以关注我的公中号:李哥技术

    总结

    其实缓存雪崩的理解很简单,为什么说得这么复杂,原因很简单,就是不想让大家用背八股文一样的方式去记忆,而是靠深入理解它的痛点然后逐步分析解决方案去记忆。

    来总结一下吧。

    概念:缓存雪崩指的是大片大片的缓存数据同时过期失效,再加上高并发的请求进入到慢设备,慢设备压力剧增,有可能导致慢设备宕机,这便是缓存雪崩。

    解决方案:

    1. 修改数据放入缓存的时间,或修改数据在缓存中的过期时间;

    2. 让缓存数据永不过期;

    3. 互斥锁,由高并发转换成低并发,保护DB;

    4. 热点隔离,实时热点发现系统;

    5. 水平扩容数据库,压力平摊,保护DB;

    6. 提前压测,得出阈值,限流处理,保护服务与DB;

    好了,本期缓存雪崩的解决思路就到这里了,感谢阅读!

    可以的话,赏个关注,也可以分享点赞再看哦~

    展开全文
  • 1. 缓存雪崩 (1). 什么是缓存雪崩? (2). 分析: (3). 解决方案: 2. 缓存击穿 (1). 什么是缓存击穿? (2). 分析: (3). 解决方案: 3. 缓存穿透 (1). 什么是缓存穿透? (2). 分析: (3). 解决方案:
  • 缓存穿透,缓存击穿,缓存雪崩详解及解决办法

    千次阅读 多人点赞 2021-12-30 10:38:07
    大部分情况下,加缓存的目的是:为了减轻数据库的压力,提升系统的性能,如果在项目中引入了缓存,可能会给我们带来的下面这三大问题。看看你中招了没? 1.缓存穿透 1.1 我们是如何用缓存的? 一般情况下,如果有...
  • 解决缓存雪崩问题

    2018-01-19 17:32:56
    在java开发中如何解决缓存雪崩的问题,因为缓存失效导致数据未加载到缓存中,或者缓存同一时间大面积的失效 从而导致所有请求都去查询数据库,导致数据库CPU和内存负载过高,甚至宕机
  • 缓存雪崩是指只大量热点key同时失效的情况,如果是单个热点key,在不停的扛着大并发,在这个key失效的瞬间,持续的大并发请求就会击破缓存,直接请求到数据库,好像蛮力击穿一样。但当缓存中大量热点缓存采用了相同...
  • 当发生缓存雪崩或击穿时,数据库中还是保存了应用要访问的数据,一旦缓存恢复相对应的数据,就可以减轻数据库的压力,而缓存穿透就不一样了。当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时...
  • 参考连接:redis避免缓存穿透为什么缓存空对象而不是null? - 知乎 缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。... 缓存雪崩:当.
  • 缓存雪崩 缓存雪崩指的是大量的请求无法在 Redis 缓存系统中处理,请求全部打到数据库,导致数据库压力激增,甚至宕机。 出现该原因主要有两种: 大量热点数据同时过期,导致大量请求需要查询数据库并写到缓存; ...
  • 比如,在初始化缓存的时候,给这些数据的过期时间增加一个较小的随机数,这样一来不同数据的过期时间有所差别又差别不大,即避免了大量数据同时过期又能保证这些数据在相近的时间失效。初始化缓存数据的时候设置缓存...
  • 这就是缓存雪崩的场景; 解决缓存雪崩可以从下面的几点着手: 1.保持缓存层的高可用 使用Redis哨兵模式或者Redis集群部署方式,即是个别Redis节点下线,整个缓存层依然可以使用。除此之外还可以在多个机房部署Redis,...
  • Redis 缓存穿透、缓存击穿和缓存雪崩问题
  • 造成缓存雪崩的关键在于同一时间的大规模的key失效,为什么会出现这个问题,主要有两种可能:第一种是Redis宕机,第二种可能就是采用了相同的过期时间。搞清楚原因之后,那么有什么解决方案呢?(1)事前① 均匀过期...
  • 前言:设计一个Redis缓存系统,不得不要考虑的问题就是:缓存穿透、缓存击穿与失效时的雪崩效应。先来看一个常见的缓存使用方式:读请求来了,先查下缓存缓存有值命中,就直接返回;缓存没命中,就去查数据库,...
  • 有什么解决方案来防止缓存雪崩? 有什么解决方案来防止缓存雪崩?</p>
  • Redis缓存雪崩

    2022-06-10 14:13:31
    1. Redis缓存雪崩问题描述 2. Redis缓存雪崩解决方案
  • 缓存穿透,缓存雪崩,缓存击穿

    千次阅读 2022-03-20 15:47:32
    一,缓存穿透 原因:一个请求来访问某个数据,发现缓存中没有,直接去DB中访问。此种情况就是穿透。(正常情况下缓存跟数据库中数据都是存在,异常情况下会导致) 方法: 1.添加参数校验,校验传递的值是否合法,再...
  • redis中,使用缓存时常见三种情况以及解决办法。
  • redis 缓存穿透,缓存击穿,缓存雪崩

    千次阅读 多人点赞 2022-04-19 15:55:51
    缓存穿透,缓存击穿,缓存雪崩
  • Redis缓存穿透、缓存雪崩和缓存击穿

    千次阅读 多人点赞 2021-09-03 10:49:02
    3.1 什么是缓存雪崩 缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。 常见缓存雪崩出现原因:1、redis服务器挂掉了。2、对缓存数据设置了相同的...
  • 缓存穿透和缓存雪崩

    2021-09-26 02:24:19
    缓存穿透和缓存雪崩其实是在项目中会遇到的两种情况,它们是两种概念。 缓存穿透: 其实就是你原本在程序和数据库中间做了缓存,程序运行时需要的数据很多可以从缓存中拿取,不用每次都访问数据库,从而给...
  • 关于缓存雪崩、击穿、穿透的解决方案前言缓存雪崩缓存雪崩的原因解决方案缓存击穿解决方案缓存穿透解决方案布隆过滤器布隆过滤器原理布隆过滤器如何使用在Java中使用布隆过滤器 前言 关于缓存异常,我们常见的有三个...
  • redis缓存穿透、缓存击穿和缓存雪崩

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 44,702
精华内容 17,880
关键字:

缓存雪崩

友情链接: MIC29150293002950029750.zip