在使用 Redis 作为缓存时,可能会遇到几种典型的问题:缓存雪崩、缓存穿透和缓存击穿。这些问题都可能导致系统性能急剧下降甚至服务不可用。下面分别介绍这三种情况以及对应的解决方案。
一、缓存雪崩
1、描述
缓存雪崩指的是当大量缓存数据在同一时间点过期(例如,由于设置了相同的 TTL),导致这些请求直接打到了后端数据库,造成数据库瞬间压力剧增,进而可能导致整个系统崩溃的情况。
2、解决方案
- 设置不同的过期时间:避免所有缓存同时过期,可以为每个缓存项设置一个随机的过期时间,比如在基础的过期时间上加上或减去一个随机数。
- 使用互斥锁排队机制:当检测到某个缓存项失效时,使用互斥锁确保只有一个线程去重新加载该缓存,其他请求等待直至缓存被成功更新。
- 热点数据永不过期:对于非常重要的热点数据,可以考虑不设置过期时间,而是通过后台任务定期更新缓存内容。
- 降级策略:设计合理的降级策略,如当数据库负载过高时,暂时返回默认值或部分结果给用户。
(1)是在业务系统中实现服务熔断或请求限流机制。
(2)事前预防:构建redis 高可用集群。
二、缓存穿透
1、描述
缓存穿透是指查询一个实际上不存在的数据,因为数据库中没有这条记录,所以每次请求都会穿过缓存层直达数据库,这样不仅增加了数据库的压力,还可能被恶意利用进行攻击。
2、解决方案
- 缓存空对象:即使查询的结果为空,也把它缓存起来,并设置较短的有效期,防止频繁访问不存在的数据。
- 布隆过滤器(Bloom Filter):用于快速判断一个元素是否存在于集合之中。可以在访问数据库之前先通过布隆过滤器检查,如果布隆过滤器认为该元素不存在,则直接返回,无需查询数据库。
- 接口层面加强校验:增加参数校验,限制非法请求进入系统。
三、缓存击穿
1、描述
缓存击穿针对的是高并发场景下对同一个热点 key 的大量请求,在这个 key 过期的一瞬间,所有的请求都会穿透到数据库,造成瞬时的高并发读取压力。
2、解决方案
- 设置热点数据永不过期:对于那些经常被访问且不太可能变化的数据,可以将其缓存设置为永远不过期,或者只在后台异步更新缓存内容。
- 互斥锁机制:当发现某个热点 key 刚好过期时,第一个请求获取到锁并负责从数据库加载最新数据回填缓存,而其他请求则等待锁释放后再从缓存读取数据。
- 双key策略:除了主缓存外,还可以维护一个辅助缓存,专门用来应对这种高并发下的缓存重建过程。
综上所述,面对缓存雪崩、穿透和击穿等问题,关键在于合理地设计缓存策略,包括但不限于如何设定缓存的有效期、如何处理不存在的数据以及如何在高并发情况下保护数据库免受冲击。根据具体的业务场景选择合适的解决方案至关重要。