系统的并发量越来越高,数据库面对大量的请求压力越来越大,所以引入了缓存技术,将高频率查询的热点数据写入缓存中,将缓存放在数据库前面,请求进来后,先从缓存中查询数据,若拿到数据则直接返回结果,若拿不到数据则请求数据库从数据库中取,数据库取到数据后更新缓存,并且返回结果,若数据库没取到,则直接返回空结果。

未添加缓存:

Snipaste_2022-12-30_09-51-14

添加缓存后:

Snipaste_2022-12-30_09-53-58

添加了缓存后,可能会出现缓存穿透、缓存雪崩、缓存击穿等问题

缓存穿透

客户端请求的数据,缓存和数据库中都没有。这样的请求缓存永远不会生效,所有的请求都会被打到数据库中,并且很有可能是恶意攻击。

常见的解决方案:

  • 缓存空对象
    • 优点:简单、维护方便
    • 缺点:有额外的内存消耗、可能造成短时间的数据不一致问题!

Snipaste_2022-12-31_09-38-52

  • 布隆过滤器
    • 优点:内存占用小
    • 缺点:实现复杂、可能存在误判问题

Snipaste_2022-12-31_09-46-01

其它的优化手段:

  • 增加 id 的复杂度,避免被猜测 id 规律
  • 做好数据的基础格式校验
  • 加强用户权限校验
  • 做好热点参数的限流

缓存雪崩

在同一时间段大量的缓存同时实现或者Redis宕机,导致大量的请求在同一时间段发送到了数据库。

Snipaste_2022-12-31_11-09-49

常见的解决方案:

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

缓存击穿

缓存击穿问题也称为热点key问题,一个高并发访问并且重建业务较复杂耗时较久的 Key 突然失效,导致大量的请求瞬间到达数据库。

常见的解决方案:

  • 互斥锁:在缓存未命中时,先尝试获取锁,获取锁成功后再进行查询数据库重建缓存。若此时有其它线程来获取锁,则会获取锁失败并且等待一段时间再重试。

Snipaste_2022-12-31_11-32-01

  • 逻辑过期:存储数据时,添加一个字段存储过期时间,存入 Redis 时,不设置 TTL

Snipaste_2022-12-31_11-44-36

解决方案 优点 缺点
互斥锁 没有额外的内存消耗; 保证一致性; 实现简单 线程需要等待,性能受影响; 可能有死锁问题
逻辑过期 线程无需等待,性能较好 不保证一致性; 有额外的内存消耗; 实现复杂
文章作者: 临川
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 临川羡鱼
Redis Redis
喜欢就支持一下吧