本文参考哔哩哔哩黑马redis实战篇
缓存更新策略
· | 内存淘汰 | 超时剔除 | 主动更新 |
---|---|---|---|
说明 | 不用自己维护,利用redis的内存淘汰机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存 | 给缓存添加ttl时间,到期后自动删除缓存,下次查询时更新缓存 | 编写业务逻辑,在修改数据库的同时,更新缓存 |
一致性 | 差 | 一般 | 好 |
维护成本 | 无 | 低 | 高 |
业务场景
- 低一致性需求:使用内存淘汰机制。比如店铺类型的查询缓存
- 高一致性需求:主动更新,并以超时剔除为兜底方案。如店铺详情缓存
主动更新策略
-
Cache Aside Pattern(路旁缓存模式)
缓存调用者在更新数据库的同时更新缓存
操作缓存和数据库时有三个问题要考虑:
- 删除缓存还是更新缓存
- 更新缓存:每次更新数据库都更新缓存,无效写操作过多(即应用一直都执行写操作而不执行读操作)
- 删除缓存:更新数据库时让缓存失效,查询时再更新缓存(推荐使用)
- 如何保证缓存与数据库操作的同时成功或失败
- 单体系统:将缓存与数据库操作放在一个事务
- 分布式系统:利用TCC等分布式事务方案
- 先操作缓存还是先操作数据库
-
一般来说应该使用先操作数据库再删除缓存
下图是两种操作发生缓存数据库不一致情况
既然两种方式都会发生错误但是还是选择先操作数据库再删除缓存:
因为缓存写入速度比修改数据库操作快,异步情况下发生错误的概率比较小缺陷 1:首次请求数据一定不在 cache 的问题 解决办法:可以将热点数据可以提前放入 cache 中。 缺陷 2:写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率 。 解决办法: * 数据库和缓存数据强一致场景 :更新 db 的时候同样更新 cache,不过我们需要加一个 锁/分布式锁(加锁的原因是更新数据库后更新缓存的时候其他线程来读取缓存内容就会 导致暂时的数据不一致)来保证更新 cache 的时候不存在线程安全问题。 * 可以短暂地允许数据库和缓存数据不一致的场景 :更新 db 的时候同样更新 cache, 但是给缓存加一个比较短的过期时间,这样的话就可以保证即使数据不一致的话 影响也比较小。
-
- 删除缓存还是更新缓存
-
Read/Write Through Pattern(读写穿透)
该模式下服务端把缓存作为主要数据存储,从中读写数据,而由缓存将此数据读取和写入 数据库,因此减轻了应用程序的维护和编写,但是我们经常使用的分布式缓存并没有提供 这种功能
写操作:
读操作:
-
Write Behind Pattern(异步缓存写入)
Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务 来负责 cache 和 db 的读写。但是,两个又有很大的不同:Read/Write Through 是同步 更新 cache 和 db,而 Write Behind 则是只更新缓存,不直接更新 db,而是改为异步 批量的方式来更新 db。