缓存击穿、穿透、雪崩

当请求比较多的时候,频繁地访问数据库会给数据库带来比较大的压力,所以此时我们会使用缓存作为缓解数据库压力的一种方式。

常见的缓存更新策略

  • Cache Aside(旁路缓存)策略

    • 当修改数据时,由应用程序来更新数据库,然后同时由应用程序来更新或者删除缓存
    • 低一致性需求:使用Redis的内存淘汰机制, 最多加上超时删除来兜底。
    • 高一致性需求:主动更新,并以超时删除作为兜底方案。
  • Read/Write Through(读穿/写穿)策略

    • Read/Write Through是应用程序只和缓存交互,不再和数据库交互。让缓存和数据库交互,相当于更新数据库的操作由缓存进行
      • Read Through: 查询缓存中数据不存在时,由缓存中间件负责从数据库查询数据,并将结果写入到缓存组件,最后缓存组件将数据返回给应用
      • Write Through: 当有数据更新的时候,先更新缓存中的数据,并且由缓存组件同步更新到数据库中,然后缓存组件告知应用程序更新完成
    • 常用的缓存中间件,如Redis,往往不提供这种方式。所以业务场景中不常用
  • Write Back(写回)策略

    • Write Back策略在更新数据的时候,只更新缓存,同时将缓存数据设置为脏的,然后立马返回,并不会更新数据库。之后会通过批量异步更新的方式来更新数据库
    • Write Back 策略特别适合写多的场景, 但是带来的问题是,数据不是强一致性的,而且会有数据丢失的风险
    • Write Back常用于计算机底层。比如 CPU 的缓存、操作系统中文件系统的缓存都采用了Write Back策略. 当电脑在突然断电之后,之前写入的文件会有部分丢失,就是因为 Page Cache 还没有来得及刷盘造成的.

我们的写业务代码时通常使用旁路缓存策略,有可能出现缓存击穿、穿透、雪崩问题。

缓存雪崩

所谓缓存雪崩,一般有两种情况。

  • 同一时间大量的key都过期了,导致访问这些key的大量请求访问数据库。
  • redis宕机了,导致大量请求访问数据库。

解决方案

  • 如果是大量key同一时间过期,则给key添加固定的过期时间的基础上, 再增加一个随机的过期时间。
  • 如果是Redis宕机, 那么就使用主从或者集群保证Redis高可用。
  • 最后,做好缓存雪崩的预防是一方面。另一方面,从服务保护的角度来说,要做好服务的限流,降级,熔断策略。即使万一发生了雪崩,也能让系统提供一定程度的服务,不至于整个宕机。

缓存穿透

缓存穿透: 请求的数据在数据库和缓存中都不存在, 那么请求就会直接访问数据库.

解决方案

  • 可以缓存空对象.
    • 优点是实现简单, 维护方便
    • 缺点是空对象会带来额外的内存消耗, 有可能出现短暂的数据不一致问题, 当每次请求的key都不一样时失效
  • 使用布隆过滤器。
    • 优点是不会有多余key, 内存占用少
    • 缺点是实现复杂, 且有误判的可能

缓存击穿

缓存击穿: 缓存击穿问题也叫热点Key问题,就是一个被大量请求访问的key突然失效了,大量请求打到了数据库上。

解决方案

  • 互斥锁: 如果redis中没查到数据, 缓存未命中. 则获取互斥锁(setnx), 获取失败则休眠重试, 获取成功则再次查询缓存是否存在(双重检测), 没查到则查询数据库进行缓存重建
    • 互斥锁注重一致性, 但是性能较差, 需要数据库与缓存强一致性选择互斥锁.
  • 逻辑过期: 缓存数据时不设置过去时间,需要在将要缓存的数据中加上时间属性作为逻辑过期时间. 当缓存命中则判断是否过期, 未过期直接返回数据, 过期则获取互斥锁. 获取锁失败则说明已经有人进行缓存重建了, 那么直接返回旧数据. 获取锁成功(需要双重检测)则开启新线程进行缓存重建, 原线程直接返回保证效率.
    • 逻辑过期性能好, 但是一致性差, 需要高性能选择逻辑过期.
相关推荐
Marktowin5 小时前
Mybatis-Plus更新操作时的一个坑
java·后端
赵文宇5 小时前
CNCF Dragonfly 毕业啦!基于P2P的镜像和文件分发系统快速入门,在线体验
后端
程序员爱钓鱼6 小时前
Node.js 编程实战:即时聊天应用 —— WebSocket 实现实时通信
前端·后端·node.js
Libby博仙6 小时前
Spring Boot 条件化注解深度解析
java·spring boot·后端
源代码•宸7 小时前
Golang原理剖析(Map 源码梳理)
经验分享·后端·算法·leetcode·golang·map
小周在成长7 小时前
动态SQL与MyBatis动态SQL最佳实践
后端
瓦尔登湖懒羊羊7 小时前
TCP的自我介绍
后端
小周在成长7 小时前
MyBatis 动态SQL学习
后端
子非鱼9217 小时前
SpringBoot快速上手
java·spring boot·后端