缓存穿透、缓存雪崩、缓存击穿

简介: 缓存穿透、缓存雪崩、缓存击穿介绍

在应用开发过程中,必然缺少不了缓存的使用,合理的设计和使用缓存不但对系统性能会有指数级的提升,还可以起到保护数据库的作用。
但是使用缓存的过程中也会有一些实战中遇到的问题,就是我们常听到的缓存穿透、缓存雪崩、缓存击穿问题,下面分别从问题产生原因、问题解决方法两方面结合实战案例来分别论述下。


一、缓存穿透


1.1 原因分析



如上图所示,请求首先经过缓存,缓存没有会进行数据库请求,当数据库查询到数据会返回到缓存层进行数据缓存,之后的请求都会被缓存层命中直接返回,起到保护数据库的作用。而有一种特殊情况是如果请求的数据在数据库中也不存在,无法完成缓存层缓存数据,在这种情况下缓存层无法起到保护数据库的作用,而是被请求直接穿透打到数据库上。
那么什么样的请求连数据库都没有数据呢?一般分为恶意请求和真实请求。恶意请求的请求方会故意编写不存在的业务数据进行请求,比如你的接口定义是传入userId获取用户信息,恶意请求故意编写一个00000000或XXXXXXXX这样基本不可能存在的userId来频繁请求接口,类似请求都会导致缓存穿透。还有一种就是真实业务请求,比如当前接口还是通过userId来请求查看当前用户是否是VIP用户,而数据库只存已经成为VIP的用户信息,而现实场景是VIP用户体量可能很小只占10%,其他90%的用户请求都无法进行缓存,大部分请求都穿透了缓存,数据库承受了大量qps。


1.2 解决方案



针对以上缓存穿透产生的原因,一般方案如上图所示的缓存空值,另外就是借助布隆过滤器。
当业务请求查询数据库也没有数据时,不是直接返回,而是和请求到数据一样,对空数据进行缓存,这样在下次请求数据时缓存层数据能够直接返回起到保护数据库的作用,规避了缓存穿透对数据库带来的威胁。
关于布隆过滤器的介绍这里不做概述,大家可以根据它的优点和缺点去分场景应用,这里不做概述。


1.3 方案优化



当缓存空值解决了缓存穿透的问题,同时也带来新的问题,那就是数据不一致。如果缓存空值的数据,在未来的某一时刻有了新的数据,这时候之前缓存的空值对于当前业务场景来说就是脏数据。比如,之前请求userId是Tomcat的用户的确是非VIP用户,我们缓存他的空值结果为非VIP,可能过了一会Tomcat想通了,进行了充值摇身一变成为了VIP用户,这时候业务请求不能再返回之前的空值非VIP用户数据了,否则业务数据就出现不一致造成数据污染也会严重影响该用户在平台的其他业务状态及服务体验。
因此,需要在业务逻辑变更时进行缓存刷新操作,一般可以删除历史缓存将新业务数据同步写入到缓存中起到数据更新的目的,保证数据一致性。


二、缓存雪崩


2.1 原因分析



缓存雪崩这个词顾名思义,非常形象,就是缓存数据集体瞬间像雪崩一样失效,这时缓存层就如同坍塌,保护数据库的这层屏障消失了。


2.2 解决方案



避免缓存雪崩产生的方法就是避免设置同一时间所有缓存失效,通常做法是将缓存时间设置成不同阈值,让缓存不会在同一时刻同时失效。


三、缓存击穿


3.1 原因分析



这里说的缓存击穿,其实和缓存穿透的含义差不多,都是因为请求绕过了缓存直接打到数据库,但是形成原因不同。可以看上图,做数据缓存时,请求到数据库数据后会将数据缓存,当缓存未有数据更新时大批量请求同时抵达,这时即使做了缓存逻辑,但是由于从数据库拿到数据更新到缓存需要时间,在这个间隙期间产生了缓存击穿现象。


3.2 解决方案



避免上述所说的缓存击穿,可以在数据库返回结果到缓存数据更新这个间隙期间增加分布式锁来解决,当缓存数据更新完成释放分布式锁,在加锁期间所有请求直接返回起到保护数据库的作用,这里特别注意的是对分布式锁要设置合理地过期时间,比如可能这个业务请求在1s内可以完成,那么可以设置5s,在较长的时间内确保可以完成缓存更新操作即可,完成后主动移除分布式锁,所有的分布式锁都要设置合理的过期时间避免产生“死锁”使业务逻辑产生问题。

除了分布式锁来控制防止缓存穿透问题的出现,还可以如上图,在查询缓存没有时直接将缓存更新成空值,确保其他线程请求后直接返回空值起到保护数据库的作用,之后当前线程查询到数据库数据直接返回更新缓存成真实数据,如果没查到也不进行缓存更新了。

相关文章
|
1月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
1月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
这篇文章介绍了如何在SpringBoot项目中整合Redis,并探讨了缓存穿透、缓存雪崩和缓存击穿的问题以及解决方法。文章还提供了解决缓存击穿问题的加锁示例代码,包括存在问题和问题解决后的版本,并指出了本地锁在分布式情况下的局限性,引出了分布式锁的概念。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
|
1月前
|
缓存 数据库
缓存穿透和击穿
【8月更文挑战第16天】
35 0
缓存穿透和击穿
|
1月前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
2月前
|
canal 缓存 NoSQL
Redis常见面试题(一):Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;先删除缓存还是先修改数据库,双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
Redis常见面试题(一):Redis使用场景,缓存、分布式锁;缓存穿透、缓存击穿、缓存雪崩;双写一致,Canal,Redis持久化,数据过期策略,数据淘汰策略
|
1月前
|
存储 缓存 NoSQL
基于SpringBoot+Redis解决缓存与数据库一致性、缓存穿透、缓存雪崩、缓存击穿问题
这篇文章讨论了在使用SpringBoot和Redis时如何解决缓存与数据库一致性问题、缓存穿透、缓存雪崩和缓存击穿问题,并提供了相应的解决策略和示例代码。
62 0
|
2月前
|
缓存 数据库
高并发架构设计三大利器:缓存、限流和降级问题之应对缓存击穿问题如何解决
高并发架构设计三大利器:缓存、限流和降级问题之应对缓存击穿问题如何解决
|
2月前
|
缓存 NoSQL Redis
使用Redis实现缓存穿透的解决方案
使用Redis实现缓存穿透的解决方案
|
14天前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
30天前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
58 0