缓存双写一致性的套路

对于缓存可能很多小伙伴会有疑问,到底是更新缓存还是删除缓存? 到底是先更新数据库,再删除缓存,还是先删除缓存,再更新数据库?>

这篇文章主要分享为了达到最终一致性,针对不同的场景,一些更新缓存的套路。

Cache Aside Pattern(旁路缓存模式)


适用于读多写少的场景,应该是目前最常用的方式。

实现逻辑

  • 读请求中,先请求缓存,若缓存命中,则直接返回缓存中的数据;若缓存未命中,则查询数据库并将查询结果更新至缓存,然后返回查询出的数据。

  • 写请求中,先更新数据库,再删除缓存。

在这种方式中,读请求很好理解,相信大部分小伙伴都是这么做的。而对于写请求相信会有不同的看法,为什么不是更新缓存?

如果是更新缓存,在并发的情况下,线程A写请求,先去更新了数据库。此时,线程B也是写请求进来更新了数据库,然而线程A因为某些原因没还去更新缓存(网络延迟等)。线程B先完成了更新缓存,线程A才完成了更新缓存。这时缓存中是线程A的旧数据,数据库中是线程B的新数据。

删除缓存就没有并发问题了吗,还是有,但是出现的概率非常小

有人会问如果删除缓存失败呢,对于这种情况那就需要采取一定的补偿机制,例如通过引入消息队列,将删除失败的缓存对应的 key 放入消息队列中,在对应的消费者中获取删除失败的 key ,异步重试删除等。

Read/Write Through Pattern


Read-Through(读穿透模式)

实现逻辑

对比Cache Aside Pattern 模式中读请求,不同点在于 Read-Through 中多了一个缓存服务,访问控制层。Cache Aside 是由调用方负责把数据加载入缓存,而Read-Through 则是通过缓存服务来完成缓存层及持久化层交互

Write Through(直写模式)

实现逻辑

对比Cache Aside Pattern 模式中写请求,Write-Through 除了多了一个访问控制层,还由之前的删除缓存变成了更新缓存,那就会出现上面的并发问题。Write-Through 直写模式适合写操作较多,并且对一致性要求较高的场景,在应用 Write-Through 模式时,也需要通过一定的补偿机制来解决它的问题。

Write-Behind(异步回写模式)


实现逻辑

可以看到Write-Behind 也有一个访问控制层,最大的区别在于该模式在更新数据的时候,只更新缓存,不更新数据库,然后通过缓存会异步地批量更新数据库数据。基于这种实现方式,数据库和缓存的一致性较弱,而且可能会丢失数据。但是异步更新数据库,我们可以合并同一数据的多次操作去更新,减少了I/O交互,减轻了数据库的压力,具有较好的吞吐性,显然这种方式适用于大量写操作的场景。

总结

对于解决缓存双写一致性问题,我们最好是按照已有的套路来解决,毕竟是经过大量验证的。当然对于具体选用哪种模式,需要结合实际业务场景来考虑,不同的模式,存在不同的优缺点,缺点我们可以通过额外的机制来处理(设置缓存过期时间,补偿机制等)。

相关推荐
dleei7 分钟前
MySql安装及SQL语句
数据库·后端·mysql
SweetCode10 分钟前
裴蜀定理:整数解的奥秘
数据结构·python·线性代数·算法·机器学习
CryptoPP22 分钟前
springboot 对接马来西亚数据源API等多个国家的数据源
spring boot·后端·python·金融·区块链
ゞ 正在缓冲99%…23 分钟前
leetcode76.最小覆盖子串
java·算法·leetcode·字符串·双指针·滑动窗口
xuanjiong24 分钟前
纯个人整理,蓝桥杯使用的算法模板day2(0-1背包问题),手打个人理解注释,超全面,且均已验证成功(附带详细手写“模拟流程图”,全网首个
算法·蓝桥杯·动态规划
清风絮柳26 分钟前
52.个人健康管理系统小程序(基于springboot&vue)
vue.js·spring boot·毕业设计·前后端分离·健康管理系统·个人健康管理系统·个人健康管理小程序
Source.Liu36 分钟前
【学Rust写CAD】27 双线性插值函数(bilinear_interpolation.rs)
后端·rust·cad
yinhezhanshen40 分钟前
理解rust里面的copy和clone
开发语言·后端·rust
惊鸿.Jh43 分钟前
【滑动窗口】3254. 长度为 K 的子数组的能量值 I
数据结构·算法·leetcode
明灯L43 分钟前
《函数基础与内存机制深度剖析:从 return 语句到各类经典编程题详解》
经验分享·python·算法·链表·经典例题