如何选择缓存的读写策略?
上一篇讲的是:
为什么需要缓存,以及缓存能解决什么问题。
这一篇开始进入缓存设计的核心:
缓存到底应该如何和数据库配合?
因为缓存最大的难题从来不是性能,而是:
数据一致性。
数据库中的数据会不断变化,而缓存中的数据是数据库的一份副本。
所以必须解决:
数据库更新了
缓存怎么办?本文聚焦在:
缓存与数据库之间的几种读写模式,以及它们各自适用于什么场景。
一、缓存设计的核心矛盾
缓存系统永远面临一个矛盾:
性能与一致性如果:
每次都访问数据库
一致性最高
性能最低如果:
全部访问缓存
性能最高
一致性最差因此:
所有缓存策略本质上都在权衡:
「性能」和「一致性」。
二、Cache Aside(旁路缓存模式)
这是互联网最主流的方案。
也是文章重点介绍的方案。
读流程
请求
↓
查缓存
↓
命中
↓
返回
未命中
↓
查数据库
↓
写缓存
↓
返回即:
Cache Miss
↓
DB
↓
Cache写流程
更新数据库
↓
删除缓存注意:
不是更新缓存。
而是:
删除缓存。
为什么删除而不是更新
例如:
数据库:
Tom更新为:
Jack如果:
更新数据库
↓
更新缓存那么:
缓存更新失败时:
DB = Jack
Cache = Tom数据不一致。
而:
更新数据库
↓
删除缓存后续请求:
缓存失效
↓
查数据库
↓
重建缓存最终一定会恢复正确。
因此:
互联网系统普遍采用:
更新数据库 + 删除缓存。
三、Read Through
另一种模式:
应用只访问缓存。
流程:
应用
↓
缓存
↓
数据库如果缓存没有:
缓存组件自动读取数据库。
特点:
业务代码简单因为:
业务层不用关心缓存失效。
但:
缓存系统需要:
- 数据加载
- 数据同步
实现复杂。
因此:
国内互联网公司很少采用。
四、Write Through
Write Through:
写缓存时同步写数据库。
流程:
应用
↓
缓存
↓
数据库写操作:
Cache
↓
DB同时完成。
优点:
数据一致性较好。
缺点:
写延迟高。
因为:
每次写都必须落数据库。
所以:
性能一般。
五、Write Back(Write Behind)
这是性能最高的写策略。
流程:
写缓存
↓
立即返回
↓
异步写数据库例如:
更新库存
↓
Redis
↓
返回成功稍后:
Redis
↓
MySQL异步同步。
优点:
性能极高。
因为:
请求根本不用等待数据库。
六、Write Back 的风险
最大问题:
数据丢失。
例如:
写入Redis还没来得及同步数据库。
Redis 崩了。
结果:
数据永久丢失因此:
Write Back 通常用于:
允许少量数据丢失
例如:
- 浏览量
- 点赞数
- 统计数据
不适用于:
订单
支付
账户余额七、几种策略的对比
| 模式 | 读性能 | 写性能 | 一致性 | 复杂度 |
|---|---|---|---|---|
| Cache Aside | 高 | 高 | 较好 | 低 |
| Read Through | 高 | 高 | 较好 | 中 |
| Write Through | 高 | 中 | 好 | 中 |
| Write Back | 高 | 最高 | 最差 | 高 |
八、为什么互联网系统几乎都用 Cache Aside
文章重点强调:
虽然缓存策略很多。
但实际工程中:
Cache Aside 几乎是事实标准。
原因:
1. 实现简单
业务自己控制缓存逻辑。
2. 不依赖缓存产品
Redis、Memcached 都能用。
3. 数据一致性容易保证
采用:
更新数据库
↓
删除缓存即可。
4. 故障影响小
缓存挂了:
最多:
回源数据库系统还能工作。
九、Cache Aside 的经典并发问题
文章专门提到:
即使采用:
更新数据库
↓
删除缓存仍然可能出现脏数据。
例如:
线程A:
查数据库准备写缓存
同时:
线程B:
更新数据库
↓
删除缓存结果:
线程A又把旧数据写回缓存:
于是:
DB = 新值
Cache = 旧值这就是:
缓存一致性问题。
后续章节会专门讲解决方案。
十、本章最核心的工程思想
很多人学习缓存时会陷入误区:
有没有一种策略能同时做到:
- 极高性能
- 强一致性
- 零复杂度
答案是:
没有。
缓存设计本质上就是取舍。
你必须在:
性能
一致性
复杂度之间平衡。
十一、本章核心脉络
数据库压力大
↓
引入缓存
↓
缓存与数据库如何同步
↓
Cache Aside
Read Through
Write Through
Write Back
↓
比较性能和一致性
↓
互联网最终选择
Cache Aside一句话总结
缓存设计的核心问题是如何在性能和一致性之间取得平衡。常见的缓存读写策略包括 Cache Aside、Read Through、Write Through 和 Write Back,其中 Cache Aside 通过“读时加载、写时更新数据库并删除缓存”的方式,在实现复杂度、性能和一致性之间取得了最佳平衡,因此成为互联网系统中最主流的缓存模式。