缓存与一致性
高并发系统案例必考:缓存"三大异常" + 一致性策略 + 多级缓存
一、缓存分层 / 多级缓存
用户 → CDN → Nginx 缓存 → 本地缓存(Caffeine) → 分布式缓存(Redis) → DB
- CDN:最外层,静态资源就近返回
- 反向代理缓存(Nginx):减轻应用
- 本地缓存(Caffeine/Guava):JVM 内,纳秒级,容量小
- 分布式缓存(Redis/Memcached):跨节点共享、容量大
- DB 缓存(MySQL Buffer Pool)
二、缓存三大异常 ⭐⭐⭐
这是案例分析的最爱出题点,必须能说清"是什么 + 危害 + 怎么解决":
1. 缓存穿透 Cache Penetration
现象查询不存在的数据,缓存和 DB 都没有,每次都打到 DB
原因恶意攻击、爬虫、参数异常
解决:
- 缓存空值:把 null 缓存几分钟
- 布隆过滤器:提前过滤掉一定不存在的 key
- 参数校验:对异常参数直接拦截
2. 缓存击穿 Cache Breakdown
现象单个热点 key 过期瞬间,大量请求穿透到 DB
原因热点数据 + 缓存过期
解决:
- 互斥锁(分布式锁):只允许一个线程回源,其他等待
- 热点 key 永不过期 + 后台异步更新
- 逻辑过期:在 value 内记过期时间
3. 缓存雪崩 Cache Avalanche
现象大量 key 同时失效,或 Redis 整体宕机,请求全部打到 DB
原因批量缓存同时过期、Redis 宕机
解决:
- 过期时间加随机偏移
- Redis 集群高可用(主从 + 哨兵 + Cluster)
- 多级缓存(本地兜底)
- 熔断 / 限流 保护 DB
- 提前预热
三大异常对比口诀:
穿透 = 查不存在 → 布隆 + 空值
击穿 = 单点过期 → 互斥锁 + 永不过期
雪崩 = 批量过期 → 随机过期 + 集群 + 熔断
穿透 = 查不存在 → 布隆 + 空值
击穿 = 单点过期 → 互斥锁 + 永不过期
雪崩 = 批量过期 → 随机过期 + 集群 + 熔断
三、缓存更新策略(数据一致性)⭐⭐⭐
缓存 + DB 是 两个数据源,更新顺序不同会带来不一致。
| 策略 | 顺序 | 问题 |
|---|---|---|
| Cache Aside(旁路) 推荐 | 更新 DB → 删除缓存 | 读旧值瞬时不一致(可接受) |
| Read/Write Through | 应用只操作缓存,缓存同步写 DB | 实现复杂、写性能差 |
| Write Behind(回写) | 只写缓存,异步刷 DB | 性能极高,可能丢数据 |
Cache Aside 4 种顺序对比
为什么"先更新 DB,再删除缓存"是推荐方案?
① 先删缓存再更新 DB → 并发下:删了缓存 → 旧请求读 DB 旧值并回写 → DB 更新 → 缓存还是旧值,不一致!
② 先更新 DB 再删缓存 → 极端情况会有短暂不一致,但概率极低,且可通过 延迟双删(再删一次)修复。
③ 更新 DB 再更新缓存 → 并发下 A、B 两次更新,缓存写入顺序可能颠倒。
结论:更新 DB → 删除缓存 + 延迟双删 最稳。
延迟双删
删除缓存 → 更新 DB → sleep N ms → 再删除缓存一次
四、Redis 关键考点
5 大基础数据结构
- String:计数器、缓存
- Hash:对象
- List:消息队列、最新列表
- Set:去重、共同好友
- ZSet:排行榜、延迟队列
持久化
- RDB:快照,体积小,启动快,可能丢数据
- AOF:追加日志,数据安全,体积大,恢复慢
- 混合:RDB + AOF
高可用
- 主从复制:基础
- 哨兵 Sentinel:自动故障转移
- Cluster:数据分片 + 高可用
过期 + 淘汰
- 过期策略:定时 + 惰性 + 定期
- 淘汰策略:noeviction / allkeys-lru / volatile-lru / allkeys-lfu / random / ttl(共 8 种)
五、答题模板
题型:为什么要引入缓存?属于哪个质量属性的什么战术?
"缓存通过把 热点数据放在内存,显著降低读延迟、减轻 DB 压力,提升系统 吞吐量 与 响应时间。它属于 性能 - 资源仲裁/资源管理 战术(也可视为可用性战术,通过冗余数据降低故障影响)。"
题型:如何保证缓存与 DB 一致性?
- 采用 Cache Aside 模式:先更新 DB 再删除缓存
- 极端场景采用 延迟双删,二次清理脏缓存
- 对一致性要求高的场景用 分布式锁 串行化
- 异步场景使用 消息队列订阅 DB binlog(如 Canal)精准刷新缓存
- 设定合理的 TTL 作为兜底
✅ 自测
1. 缓存穿透、击穿、雪崩各自现象与对策?
2. 为什么推荐"更新 DB → 删除缓存"而不是"更新 DB → 更新缓存"?
3. Redis 5 大基础数据结构?
📗 高频专题 · 缓存 完