image.png

维度 缓存穿透 缓存击穿 缓存雪崩
数据存在性(缓存) 曾有,批量过期后缺失
数据存在性(数据库)
触发关键 不存在的 Key(如恶意构造非法ID、攻击请求) 热点数据 + 缓存过期/失效(如热门商品缓存到期) 大量数据设置同一过期时间,或缓存服务宕机
请求量级影响 持续重复请求均落库(无缓存拦截) 并发请求集中落库(短期瞬时高并发) 批量请求集中落库(短期海量请求)
能否回写缓存 不能(数据库无对应数据) 能(数据库有热点数据,查询后可回写) 能(数据库有对应数据,查询后可回写)
问题描述 请求的Key在缓存和数据库中均不存在(如恶意构造不存在的用户ID、非法参数),所有请求均绕过缓存直接访问数据库,导致数据库持续承受无意义的请求压力,严重时可能引发数据库过载、响应延迟甚至宕机。 某一热点Key(如热门商品详情、活动入口接口)的缓存因过期/意外失效而缺失,此时大量并发请求同时访问该Key,均未命中缓存并集中涌向数据库,导致数据库短期内承受极高并发压力,可能引发瞬时过载或服务卡顿。 大量缓存Key因设置相同过期时间而在同一时刻批量过期,或缓存服务(如Redis)因故障宕机,导致海量请求无法命中缓存,全部集中访问数据库,造成数据库短时间内请求量暴增,可能引发数据库宕机,进而导致整个服务链路雪崩。
解决方案 1. 布隆过滤器:初始化时将数据库中所有存在的Key哈希到布隆过滤器,请求先经过过滤器,不存在的Key直接拦截,避免访问数据库;<br>
  1. 缓存空值:对不存在的Key缓存空值(或默认占位值),并设置短期过期时间(如1-5分钟),避免相同请求重复落库;<br>

  2. 接口层校验:在请求入口校验参数合法性(如ID格式、数值范围),拦截恶意构造的不存在Key。 | 1. 互斥锁(分布式锁):缓存缺失时,只有一个线程能获取锁并查询数据库,查询后回写缓存,其他线程等待重试(如Redis的SETNX锁);<br>

  3. 热点Key永不过期:对核心热点Key不设置过期时间,通过业务逻辑(如数据更新时主动同步)维护缓存一致性;<br>

  4. 缓存预热:高并发场景前(如活动开始前1小时),主动将热点数据加载到缓存并设置合理过期时间,避免高峰期缓存缺失。 | 1. 过期时间随机化:给每个Key的基础过期时间增加随机偏移量(如基础过期1小时+随机0-30分钟),避免批量Key同时过期;<br>

  5. 多级缓存架构:引入“本地缓存(如Guava Cache)+ 分布式缓存(如Redis)”,即使分布式缓存雪崩,本地缓存可暂存数据,减少DB压力;<br>

  6. 缓存服务高可用:部署缓存集群(如Redis Cluster)、哨兵模式,避免单点故障,确保缓存服务稳定;<br>

  7. 熔断降级机制:通过组件(如Sentinel、Hystrix)监控数据库请求量,当超过阈值时暂时拒绝部分请求或返回默认值,防止数据库被压垮。 |

## 缓存异常
### 前置知识
- 缓存穿透:数据既不在缓存中,也不在数据库中
- 缓存击穿:数据不在缓存中;高并发场景下才会有问题
- 缓存雪崩:核心:请求直接落到了数据库上
### 基本思路
- 解决缓存穿透
  - 回写特殊值
  - 布隆过滤器
- 解决缓存击穿:singleflight
- 解决缓存雪崩:过期时间增加随机偏移量
- 彻底的兜底方案:限流
  - 服务限流
  - 数据库限流
### 亮点方案
- 异地多活
- 互为备份
  - 各个业务使用自己的集群,用别人的集群作为备份
  - 业务1会和集群1保持心跳
  - 当发现连不上Redis之后,就可以执行容错方案
  - 业务1上根据流量分类处理
    - 非核心流量→直接熔断
    - 核心流量→一部分熔断;一部分转发集群2(流量要保守,别把集群2搞崩)
  - 业务1发现集群1恢复过来了→逐步将集群2的流量转发回来
- 使用廉价灾备
  - 撑住一小段时间
  - 不需要高性能,能用就行
  - 节省成本,降本增效

其他

A

B