简单聊下缓存里的几种模式。
一 Cache-Aside
- 读操作:应用先去查询缓存,命中则返回;没命中应用则会去数据库读取数据,写入缓存后返回。
- 写操作:应用先更新数据库再删除缓存,然后返回。
可以看到,这种模式下,缓存只有写入与删除而没有修改操作。
适用场景:读多写少。
存在的问题:多线程下易出现数据不一致的问题。
二 Read/Write-Through
核心思想:应用需要操作数据时只与缓存组件进行交互;缓存里的数据不会过期。
- Read-Through,应用查询缓存是否存在,存在则返回;不存在则由缓存组件去数据库加载数据。
Write-Through,先查询要写入的数据在缓存是否存在,存在则先更新缓存然后再更新数据库最后返回;如果要写入的数据在缓存不存在,有两对应策略:一种是先将数据写入缓存,然后由缓存组件将数据同步更新到数据库;另一种策略是不写缓存直接将数据写入数据库。
适用场景:读多写少。
存在的问题:- 因为应用操作数据时只与缓存组件交互,相对于Cache-Aside而言数据不一致的概率要低一些。
- 因为此模式下缓存没有过期时间,所以缓存的使用量会非常大。
三 Write-Back
Write-Back也称Write-Behind,这种模式是承接Write-Through的,在对数据进行数据持久化存储回写时一般采用异步回写,也可以间隔一定时间后批量回写
适用场景:读少写多
存在的问题:异步或间隔一定时间的批量回写会导致数据延迟或数据丢失的情形出现。
这里只是介绍了常见的缓存模式里的一些基本情况,所讨论的缓存模式都存各自的问题,需要我们根据自己的业务场景来选用适合自己的模式。当然数据丢失、热点数据、缓存穿透、缓存预热等这些问题是在使用缓存时都必须考虑的。另外数据模型也是需要注意的,在Cache-Aside下缓存里的数据模型可以与数据库数据模型不一致,而Read/Write-Through模式下二者的数据模型一般是需要相同的。
最后再附一比较全面的文章,连接:
https://mp.weixin.qq.com/s?__...
里面提到了数据一致性一般是多步骤操作时其中一步骤操作失败与并发这两种情况引起的,也介绍了各种方案及问题,比如延迟双删的场景。文章也有提到我们使用redis是为了提高性能,有的时候我们并不能保证完全一致性,只能做到最终一致性,也就是CAP里的AP(可用性与分区容错性,一致性很难)。还有一点就是使用Cache-Aside模式导致不一致的概率是最低的,我们先列下流程:
- 缓存中X不存在,数据库里X=1
- 线程A读取数据库,得到旧值X=1
- 线程B更新数据库X=2,
- 线程B删除缓存
- 线程A将旧值X=1写入缓存
为什么说Cache-Aside模式导致不一致的概率很低呢?原因如下:
- 读请求 + 写请求并发
- 缓存刚好已失效
- 更新数据库 + 删除缓存的时间(步骤 3-4),要比读数据库 + 写缓存时间短(步骤 2 和 5)
只有这三种情况都出现才会出现不致,特别是第3步出现的可能性比较小,因为更新数据的时间可能会有锁,一般会长于读的时间。
一点总结:
- 引入缓存的目的大部分是为了提升性能
- 性能与数据强一致性往往很难兼顾
- 没特殊情况,建议使用先更新数据库+再删除缓存的方式
- 延迟双删是为了缓存+主从库未及时同步的问题,删缓存操作一般通过消息队列进行,但延迟时间不好评估(先删除缓存,接着修改数据库,最后延迟一定时间再删一次缓存)
参考的文章:
https://www.pianshen.com/arti...
https://hiddenpps.blog.csdn.n...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。