Appearance
策略
| 内存淘汰 | 超时剔除 | 主动更新 | |
|---|---|---|---|
| 说明 | 不用自己维护,利用 Redis 的内存淘汰机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存。 | 给缓存数据添加 TTL 时间,到期后自动删除缓存,下次查询时更新缓存。 | 编写业务逻辑,在修改数据库的同时,更新缓存。 |
| 一致性 | 差 | 一般 | 好 |
| 维护成本 | 无 | 低 | 高 |
低一致性需求:使用内存淘汰机制,例如店铺类型的查询的缓存。
高一致性需求:主动更新,并以超时剔除作为兜底方案,例如店铺详情查询的缓存。
读操作
缓存命中直接返回
缓存未命中则查询数据库,并写入缓存,设置超时时间。
写操作
先写数据库,再删除缓存。
要确保数据库和缓存操作的原子性
主动更新
由缓存的调用者,在更新数据库的同时更新缓存,实际中使用最多。
缓存与数据库整合为一个服务,由服务来维护一致性。调用者调用该服务,无需关心缓存一致性 问题。
调用者只操作缓存,由其它线程异步的将缓存数据持久化到数据库,保证最终一致。
操作缓存与数据库时需要考虑三个问题:
删除缓存还是更新缓存
更新缓存:每次更新数据库时都更新缓存,导致无效写操作较多,比如更新了 100 次,需要写 100 次,如果没有访问,会导致无效写操作.
删除缓存:每次更新数据库时让缓存失效,查询时再更新缓存,比如更新了 100 次,只需要删 1 次,查询时再更新缓存。因此一般选择删除缓存。
如何保证缓存与数据库的操作同时成功或失败
单体系统:将缓存与数据库操作放在一个事务
分布式系统:利用 TTC 等分布式事务方案
先删除缓存还是先更新数据库
线程 1 负责删除缓存再更新数据库,删除缓存后线程 2 正好查询缓存,未命中, 去查询数据库,此时线程 1 还没能够更新数据库,导致线程 2 将数据库内容写入缓存,之后 线程 1 才更新数据库,导致缓存不一致。
线程 1 负责更新数据库再删除缓存,线程 2 由于缓存过期正好来查询缓存,未命中, 去查询数据库,查询到旧的数据,此时线程 1 更新数据库并删除缓存,之后线程 2 写入缓存, 导致缓存不一致,这种的触发条件比较苛刻,因此先更新数据库再删除缓存。