4. 缓存基础:缓存分层架构与三大经典问题

在限流熔断治理中,缓存是抵御流量冲击的第一道防线,也是保障数据一致性的关键枢纽。理解缓存的分层架构以及穿透、击穿、雪崩三大问题,是构建高可用缓存体系的前提。

4.1 缓存分层架构

现代分布式系统通常采用多级缓存策略,将数据按访问频率、延迟敏感度、一致性要求分层存放。每一层都有其特定的性能特征与适用场景。

层级 存储位置 典型延迟 容量 一致性模型 典型实现
L1 本地缓存 应用进程内(堆内存) < 1 ms MB ~ GB 最终一致(需主动失效) Caffeine, Guava Cache, Ehcache
L2 分布式缓存 独立缓存集群(网络访问) 1 ~ 5 ms GB ~ TB 强一致(Redis Cluster)或最终一致 Redis, Memcached, Tair
L3 全局共享缓存 数据库或持久化存储 10 ~ 100 ms TB ~ PB 强一致(事务保证) MySQL, PostgreSQL, TiDB
架构建议:本地缓存适合存放热点数据(如用户会话、配置项),分布式缓存承载全量热点,数据库作为最终一致性兜底。限流熔断场景下,本地缓存失效后应优先回查分布式缓存,而非直接穿透到数据库。

4.1.1 多级缓存协同流程

下图展示了一次典型的多级缓存查询路径,体现了“先近后远、逐级回退”的原则。

多级缓存查询流程 客户端请求 L1 本地缓存(Caffeine) 命中 → 直接返回 未命中 L2 分布式缓存(Redis) 命中 → 回填 L1 并返回 未命中 L3 数据库(MySQL) 查询 → 回填 L2 & L1 → 返回 回填
关键原则:回填操作必须使用异步非阻塞方式,避免阻塞主请求链路。同时,L1 缓存应设置合理的 TTL(如 30~60 秒),防止本地缓存与分布式缓存长期不一致。

4.2 缓存穿透

定义:查询一个根本不存在的数据,导致请求绕过缓存,直接打到数据库。如果并发量高,数据库会承受巨大压力,甚至宕机。

4.2.1 产生原因

  • 恶意攻击:攻击者构造大量不存在的 Key 发起请求。
  • 业务漏洞:前端未做参数校验,后端未做空值缓存。
  • 缓存未预热:新上线数据未被加载到缓存中。

4.2.2 解决方案

方案 原理 优点 缺点
空值缓存 将查询结果为 null 的 Key 也缓存起来,TTL 较短(如 5 分钟) 实现简单,通用性强 占用缓存空间,可能被恶意 Key 填满
布隆过滤器 在缓存前加一层 Bloom Filter,判断 Key 是否存在 空间效率高,不存在误判为存在 存在误判为不存在(可容忍),需定期重建
参数校验 在网关层或业务层对请求参数做合法性校验 从源头拦截无效请求 无法拦截合法但不存在的数据
注意:空值缓存虽然简单,但容易被恶意攻击者利用大量随机 Key 撑爆缓存。建议结合布隆过滤器使用,先过滤掉绝大多数不存在的 Key,再对少量漏网之鱼做空值缓存。

4.3 缓存击穿

定义:一个热点 Key 在缓存失效的瞬间,大量并发请求同时涌入,直接打到数据库,导致数据库压力骤增。

4.3.1 典型场景

  • 秒杀商品详情页:某个爆款商品的 Key 过期。
  • 热门新闻:某条新闻的缓存刚好在流量高峰时失效。
  • 全局配置:系统全局配置 Key 过期,所有服务同时回查数据库。

4.3.2 解决方案对比

方案 实现方式 适用场景 一致性影响
互斥锁(Mutex) 缓存失效后,只允许一个线程去数据库加载,其他线程等待 并发量极高,对一致性要求高 强一致,但可能增加延迟
逻辑过期 缓存永不过期,但数据中携带过期时间,异步线程发现过期后更新 允许短暂不一致,追求高可用 最终一致,实现复杂
热点 Key 永不过期 对热点 Key 不设置 TTL,由后台任务定期刷新 数据变化不频繁的热点 强一致(需保证刷新及时)
实践建议:在限流熔断场景下,推荐使用互斥锁 + 本地缓存的组合。本地缓存作为第一道屏障,即使分布式缓存击穿,本地缓存仍能扛住大部分请求,只有本地缓存也失效时才触发互斥锁回查数据库。

4.4 缓存雪崩

定义:大量缓存 Key 在同一时间失效,或缓存节点宕机,导致所有请求直接打到数据库,引发数据库崩溃,进而导致整个系统雪崩。

4.4.1 雪崩的两种形态

  • 批量失效雪崩:大量 Key 设置了相同的 TTL,在同一时刻集体过期。
  • 节点宕机雪崩:缓存集群中某个节点宕机,该节点上的所有 Key 失效,请求全部转发到数据库。

4.4.2 预防与治理措施

缓存雪崩治理策略 缓存雪崩 预防:TTL 随机化 预防:多级缓存 预防:缓存预热 治理:限流熔断 治理:高可用集群 治理:降级预案 核心思路:预防为主,治理为辅,通过多级缓存和限流熔断构建纵深防御体系

4.4.3 关键治理措施详解

  1. TTL 随机化:在基础 TTL 上增加一个随机偏移量(如 ±20%),避免大量 Key 同时过期。
  2. 多级缓存:本地缓存 + 分布式缓存组合,即使分布式缓存宕机,本地缓存仍能提供部分服务。
  3. 缓存预热:系统启动或大促前,提前将热点数据加载到缓存中,避免冷启动穿透。
  4. 限流熔断:在数据库访问层配置限流和熔断器,当数据库压力超过阈值时,直接返回降级响应。
  5. 高可用集群:Redis 采用主从 + Sentinel 或 Cluster 模式,避免单点故障。
  6. 降级预案:当缓存和数据库都不可用时,返回静态数据或默认值,保证系统基本可用。
限流熔断与缓存的协同:在缓存雪崩场景下,限流熔断是最后的保护屏障。当数据库连接池使用率达到 80% 时,应触发熔断,直接返回缓存中的旧数据或默认值,而不是继续穿透数据库。这正是本课程“缓存一致性闭环”的核心思想——在保证最终一致的前提下,优先保障系统可用性。

4.5 三大问题对比总结

问题 触发条件 影响范围 核心解决方案 与限流熔断的关系
缓存穿透 查询不存在的数据 单个 Key 反复穿透 布隆过滤器 + 空值缓存 限流可缓解,但需从源头拦截
缓存击穿 热点 Key 失效瞬间 单个热点 Key 互斥锁 + 逻辑过期 熔断可保护数据库,但会降低体验
缓存雪崩 大量 Key 同时失效或节点宕机 全局或大面积 TTL 随机化 + 多级缓存 + 高可用 限流熔断是最后一道防线