缓存穿透

缓存穿透指的是:一个缓存和数据库中都不存在的数据,由于数据库无法写入缓存,导致频繁请求直接打到数据库,从而造成数据库压力过大甚至被“打穿”。

常见的解决方法包括:缓存空值布隆过滤器

布隆过滤器由一个全 0 的位图数组n 个哈希函数组成。当一个数据在请求缓存前,会先经过布隆过滤器。过滤器会通过 n 个哈希函数计算出 n 个哈希值,再分别对数组长度取模,并将对应的数组下标置为 1。

查询时,只需要查看位图数组中这 n 个位置是否全部为 1:

  • 若存在某个位为 0,则说明该数据一定不存在于数据库中;
  • 若全部为 1,则说明该数据可能存在,但不一定真的存在,因为可能出现哈希碰撞。

因此,布隆过滤器判断“存在”时并不能保证数据真的存在,但判断“不存在”时一定准确。

缓存雪崩

缓存雪崩指的是:大量的缓存 Key 在同一时间失效,或者 Redis 服务器宕机,导致所有请求同时打到数据库,造成数据库瞬时压力过大,甚至宕机的情况。

解决方法:
为缓存设置 固定过期时间 + 随机过期时间,让不同 Key 的过期时间错开,避免在同一时间集中失效。

缓存击穿

缓存击穿指的是一个热点key设置了时间了过后 时间过期了 恰好这个时候大量请求打到数据库 让数据库压力大

解决方案:

方案一:互斥锁(分布式锁)

当缓存失效时,不立即去加载数据库,而是先使用 Redis 的 SETNX 命令设置互斥锁

  • 若设置成功(即当前线程获得锁),则执行 load db 操作并回填缓存;
  • 若设置失败(说明已有线程在加载数据),则稍后重试获取缓存

优点:保证数据一致性。
缺点:性能稍差,可能存在死锁风险。


方案二:逻辑过期

设置 Key 时,不给 Redis 设置真实的过期时间,而是在 Value 中自带一个逻辑过期时间字段
实现思路如下:

  1. 设置缓存时,将过期时间作为字段与数据一起存入;
  2. 查询时,先从 Redis 获取数据并判断逻辑时间是否过期;
  3. 若已过期,则异步开启一个线程进行数据刷新,同时返回旧数据给用户(保证高可用)。

优点:高性能、高可用。
缺点:数据可能短时间内不一致。


总结:

  • 若追求强一致性 → 使用 分布式锁方案
  • 若追求高性能、高可用性 → 使用 逻辑过期方案