1. 缓存雪崩(Cache Avalanche)
定义:
缓存雪崩指的是当缓存中大量的缓存数据在同一时间失效,导致大量的请求直接打到后端数据库,造成数据库压力剧增,甚至可能引起数据库崩溃。
发生原因:
- 大量缓存的失效时间被设置得相同(例如,所有缓存的过期时间是固定的,或者是基于相同的时间点设置的)。
- 短时间内大量的缓存数据失效,所有请求直接访问数据库,可能导致数据库短时间内的访问量急剧增加,造成数据库的压力暴增。
解决方案:
-
缓存过期时间随机化:为不同缓存设置不同的过期时间,避免在同一时间点大量缓存失效。
- 比如,缓存的过期时间可以在一个范围内随机化,比如
原定过期时间 ± 10分钟
,以避免缓存失效集中在一个时间点。
- 比如,缓存的过期时间可以在一个范围内随机化,比如
-
加锁机制:在缓存失效的情况下,通过互斥锁或分布式锁,确保只有一个请求去加载数据库数据,其他请求可以等待或者从缓存中获取之前加载的数据,避免缓存雪崩。
-
热点数据提前缓存:对于一些热数据,提前设置较长的缓存时间或采取预加载机制,避免这些数据频繁过期。
2. 缓存击穿(Cache Breakdown)
定义:
缓存击穿是指某个热点数据的缓存失效,且此时有大量请求同时访问该数据,导致所有请求直接访问数据库,从而增加数据库压力,甚至可能引发数据库崩溃。
发生原因:
- 缓存中的某个热点数据(如热门商品、热点文章等)失效,导致大量并发请求直接打到数据库。
- 同时,缓存并没有及时重新加载数据,因此请求在短时间内直接访问数据库,给数据库造成压力。
解决方案:
-
加锁机制:对于某些缓存失效的热点数据,可以通过加锁机制(如分布式锁)保证只有一个线程去查询数据库并重新加载缓存,其他线程等待加载完成后从缓存中获取数据。
-
互斥锁:可以通过 Redis 的
SETNX
命令或者使用类似Redisson
等分布式锁工具来确保同一时刻只有一个请求去更新缓存,防止缓存击穿。 -
提前加载:对于一些热点数据,定期进行缓存预热,或者当缓存即将过期时,提前加载数据。
3. 缓存穿透(Cache Penetration)
定义:
缓存穿透是指查询一个根本不存在的数据,缓存中没有,数据库中也没有,导致每次查询都直接访问数据库。即使数据不存在,所有请求都会直接访问数据库,造成数据库的压力。
发生原因:
- 请求的数据在缓存中没有,也不存在于数据库中,导致每次请求都会查询数据库,浪费资源。
- 数据不存在时,缓存没有设置适当的空值缓存,导致每次请求都打到数据库。
解决方案:
-
缓存空对象:当查询的数据不存在时,可以将空对象(例如
null
或一个特殊的标志对象)缓存一定时间。这样,下次再查询同样的数据时,就可以直接返回空对象,而不再查询数据库。 -
布隆过滤器(Bloom Filter):使用布隆过滤器判断某个数据是否存在。如果某个数据在布隆过滤器中不存在,则可以直接返回,不再查询缓存和数据库。布隆过滤器可以减少对不存在数据的数据库访问。
-
接口校验:加强接口的参数校验,避免恶意用户或无效请求访问缓存和数据库。
小结
- 缓存雪崩:指大量缓存同一时刻失效,导致数据库压力暴增。可以通过缓存过期时间随机化、加锁等方式避免。
- 缓存击穿:指热点数据的缓存失效,导致大量并发请求直接访问数据库。通过加锁、互斥锁、预加载等方式来避免。
- 缓存穿透:指查询不存在的数据,导致每次请求都直接访问数据库。可以通过缓存空对象、布隆过滤器等方式来避免。
这三个问题通常在大规模分布式缓存系统中都会面临,设计时需要采取合适的策略来确保缓存系统的稳定性和高效性。