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 缓存应设置合理的 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 预防与治理措施
4.4.3 关键治理措施详解
- TTL 随机化:在基础 TTL 上增加一个随机偏移量(如 ±20%),避免大量 Key 同时过期。
- 多级缓存:本地缓存 + 分布式缓存组合,即使分布式缓存宕机,本地缓存仍能提供部分服务。
- 缓存预热:系统启动或大促前,提前将热点数据加载到缓存中,避免冷启动穿透。
- 限流熔断:在数据库访问层配置限流和熔断器,当数据库压力超过阈值时,直接返回降级响应。
- 高可用集群:Redis 采用主从 + Sentinel 或 Cluster 模式,避免单点故障。
- 降级预案:当缓存和数据库都不可用时,返回静态数据或默认值,保证系统基本可用。
限流熔断与缓存的协同:在缓存雪崩场景下,限流熔断是最后的保护屏障。当数据库连接池使用率达到 80% 时,应触发熔断,直接返回缓存中的旧数据或默认值,而不是继续穿透数据库。这正是本课程“缓存一致性闭环”的核心思想——在保证最终一致的前提下,优先保障系统可用性。
4.5 三大问题对比总结
| 问题 | 触发条件 | 影响范围 | 核心解决方案 | 与限流熔断的关系 |
|---|---|---|---|---|
| 缓存穿透 | 查询不存在的数据 | 单个 Key 反复穿透 | 布隆过滤器 + 空值缓存 | 限流可缓解,但需从源头拦截 |
| 缓存击穿 | 热点 Key 失效瞬间 | 单个热点 Key | 互斥锁 + 逻辑过期 | 熔断可保护数据库,但会降低体验 |
| 缓存雪崩 | 大量 Key 同时失效或节点宕机 | 全局或大面积 | TTL 随机化 + 多级缓存 + 高可用 | 限流熔断是最后一道防线 |