redis缓存:雪崩、穿透、击穿详解

一、缓存三兄弟

1. 缓存雪崩(Cache Avalanche)

问题描述:

大量的缓存数据在同一时间集中失效,此时请求全部打到MySQL,造成MySQL崩溃或响应能力降低。

场景还原:

  • Redis最初是空的,需要预热
  • 大量缓存数据设置了相同的过期时间
  • Redis重启或MySQL/存储系统重启后,缓存空窗期请求全打MySQL

解决方案:

方案 说明
间隔设置过期时间 给缓存的过期时间加上随机偏移量,避免同一时间批量失效
数据预热 系统启动或重启后,提前将热点数据加载到Redis
持久化 开启Redis持久化,避免重启后缓存全空
多级缓存 引入本地缓存作为缓冲层

2. 缓存穿透(Cache Penetration)

问题描述:

查询的数据在缓存和MySQL中都不存在,请求穿透缓存直接打MySQL,如果大量恶意请求,可能导致MySQL崩溃。

场景还原:

  • 查询一个根本不存在的key
  • 恶意请求大量不存在的数据
  • MySQL成为最后一道防线,不断被无效查询击穿

解决方案:

方案 说明
缓存空值 对不存在的数据在Redis中缓存一个空值(nil标记),下次查询直接返回
布隆过滤器(Bloom Filter) 概率型数据结构,判断某个key一定不存在,存在则可能误判

布隆过滤器部署位置对比:

部署位置 优点 缺点
部署在Server端 轻量级实现 多个Server端需要初始化多个布隆过滤器,运维压力大
部署在Redis 共享一份布隆过滤器,多个Server共用 需要额外的Redis插件支持

3. 缓存击穿(Cache Breakout)

问题描述:

某个热点key在Redis中没有数据,但MySQL中有数据。大量的并发请求同时访问Redis发现没有该数据,转而全部去请求MySQL,造成MySQL崩溃。

场景还原:

  • 热点key刚好过期
  • 大量并发请求同时发现Redis没数据
  • 所有请求同时打向MySQL

解决方案:

方案 说明
分布式锁 确保只有一个请求去查MySQL,其他请求等待结果
过热数据永不过期 对极热点数据设置永不过期或后台异步续期

二、缓存架构设计

1. 整体架构

复制代码
                    +-------+
                    | Client |
                    +---+---+
                        |
                        v
+----------------+   +-------+   +------------+   +-------+
|   Write Path   |->| Redis |   | Read Path  |<---| MySQL |
+----------------+   +-------+   +------------+   +-------+
      |                              ^
      |                              |
      v                              |
+----------------+                   |
|    MySQL       |-------------------+
+----------------+

  同步中间件(伪装成MySQL从库)

2. 读写策略

读策略流程:

复制代码
Client -> Redis存在? -> Yes -> 直接返回数据
              |
              No
              v
         查MySQL -> 有数据 -> 写入Redis -> 返回数据
                   |
                   No
                   v
              返回空/错误

写策略流程:

复制代码
Client -> 写Redis(设置过期时间) -> 写MySQL
              |
              v (等待MySQL同步到Redis)
         过期时间 = Server到MySQL同步时间 + 中间件拉取数据时间 + 传输时间
              |
              v (通常设定200ms经验值)

3. 同步中间件

核心职责:

  • 伪装成MySQL从数据库
  • 同时连接MySQL和Redis
  • 拉取MySQL的binlog变更
  • 将热点数据同步给Redis

三、缓存一致性问题

脏数据问题

场景:

写Redis成功,但写MySQL失败,此时会有约200ms的脏数据时间窗口。

时间线:

复制代码
T=0ms   Client写Redis成功
T=50ms  Client开始写MySQL
T=200ms 中间件同步MySQL到Redis
        |
        v (中间T=0ms~T=200ms是脏数据窗口)

数据一致性保证

策略 说明
先写Redis再写MySQL 保证最终一致性,有短暂脏数据窗口
过期时间兜底 即使同步失败,脏数据也会在过期后自动清除
延迟双删 写完MySQL后删除Redis,再延迟一段时间后删除

四、安全性问题汇总

问题 原因 解决方案
写Redis成功写MySQL失败 网络抖动/MySQL响应慢 过期时间兜底+告警机制
Redis数据丢失 Redis重启/故障 开启持久化(RDB/AOF)
缓存雪崩 大量key同时过期 随机过期时间+数据预热
缓存穿透 查询不存在的数据 空值缓存+布隆过滤器
缓存击穿 热点key过期+并发 分布式锁+永不过期

根据零声教育教学写作https://github.com/0voice

相关推荐
SelectDB3 小时前
让变更流出 Doris:Apache Doris 5.0 基于增量计算的 CDC 技术解析
数据库
这个DBA有点耶3 小时前
MCP隔离层+行级语义审计+输出校验:AI访问数据库的安全边界拆解
数据库·人工智能·ai编程
这个DBA有点耶4 小时前
从反向扫描O(n)到正向扫描O(1):降序索引的物理机制与混合排序匹配规则
数据库
码哥字节4 小时前
缓存一致性:先删缓存还是先更新库?3 种方案对比 + 实战
redis
2501_933923255 小时前
解读Redis:单线程模型
数据库·redis·缓存
我不会起名字3225 小时前
seq 空洞排查:Mongo 的 51 只是预留上界,Redis CURR 才是已消耗边界
redis·后端·mongodb·go·即时通讯·im·故障排查
Tapdata6 小时前
被忽略的第三类上下文:Agent 进入真实业务后,还缺什么?
数据库·人工智能·架构
小科先生7 小时前
Java springboot调用数据库的基本流程
java·数据库·spring boot
星恒随风7 小时前
MySQL 从零入门(四):表的增删改查与基础查询详解
linux·服务器·数据库·笔记·mysql