# 1、缓存穿透

# 1、定义

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会被打到数据库上。image.pngimage.png

# 2、产生原因

  1. 自身业务代码问题
  2. 恶意攻击,爬虫造成空命中

# 3、常见的两种解决方案

# 缓存空对象

优点:实现简单,维护方便缺点:① 额外的内存消耗② 可能造成短期的不一致image.png

# 布隆过滤器

优点:内存占用较少,没有多余 Key 缺点:① 实现复杂② 存在误判可能image.png 补充:布隆过滤器,当再布隆过滤器中获取数据说是不存在时,那一定是不存在的,但是如果说是存在的话,数据实际上说不定是不存在的。所以使用布隆过滤器也可能会出现缓存穿透问题。

# 增强 id 的复杂度避免被猜测 id 规律

# 做好数据的基础格式校验

# 加强用户权限校验

# 做好热点参数的限流

# 2、缓存雪崩

# 1、定义

缓存雪崩是指在同一时段大量的缓存 Key 同时失效或者 Redis 服务宕机,导致大量请求到达数据库,带来巨大压力。image.pngimage.png

# 2、解决方案

  • 给不同的 Key 的 TTL 添加随机值
  • 利用 Redis 集群提高服务的可用性
  • 给缓存业务添加降级限流策略
  • 给业务添加多级缓存

# 3、缓存击穿

# 1、定义

缓存击穿问题也叫做热点 Key 问题,就是一个高并发访问并且缓存重建业务比较复杂的 Key 突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。image.png 如上图所示的,线程 1 查询缓存但是缓存并没有命中,就开始查询数据库了,然后线程 2、3、4 也陆续查询了缓存没有命中,都去查询数据库并重建缓存。导致 db 的压力猛增,造成 dp 有可能会宕机。

# 2、解决方案

# ① 互斥锁

image.png 如上图所示:线程 1 和线程 2,线程 1 先查询缓存,但是没有命中,然后线程 1 获取互斥锁,后进行查询数据库重建数据缓存,期间线程 2 查询缓存,同样没有命中,接着线程 2 获取互斥锁,但是并没有获取到锁,所以线程 2 就在等待并重试,直到线程 1 重建数据缓存并写入缓存结束后释放互斥锁,然后线程 2 获取到互斥锁缓存命中获取到数据就可以返回了。

# ② 逻辑过期

image.png 上图为逻辑过期的处理流程:线程 1 查询缓存,发现逻辑过期时间已经过期了,后获取互斥锁,然后开启新的线程:线程 2,而线程 1 直接拿旧的数据返回了,线程 2 重建数据并设置逻辑过期时间,在此时间之内线程 3 查询缓存发现逻辑过期时间过期了,并且获取互斥锁失败,那么就证明有线程在重建数据了,线程 3 就拿旧的数据返回。这时线程 2 重构数据成功,并释放了互斥锁。线程 4 过来直接直接命中缓存并且没有逻辑过期,就返回了。

# 总结:

两种方式各有优缺点:

解决方案 优点 缺点
互斥锁 没有额外的内存消耗保证一致性实现简单 线程需要等待,性能受影响可能有死锁风险
逻辑过期 线程无需等待,性能较好 不保证一致性有额外内存消耗实现复杂

建议再看一篇这个文章,写的比我好多了:十分钟彻底掌握缓存击穿、缓存穿透、缓存雪崩 - 三分恶 - 博客园