缓存和数据库一致性的理解

偶然看到一篇介绍缓存和数据库一致性文章,点进去发现写的很细,配图也很多,但是读起来过于冗长,逻辑跳跃,很难给读者留下很清晰的印象。于是又搜了其他的一些相关文章,发现内容都差不太多,颇为失望
因为本人一直以来追求清晰、明朗,所以忍不住分享一下自己的一些想法,但水平有限,若有错误,还望不吝赐教。

比较懒,以下是纯文字,所以尽量简洁

首先,我们这里讨论的缓存一致性,指的是缓存和数据库的一致性(Cache & DB Consistency),并非CPU缓存一致性

对于缓存和数据库,就目前的技术而言,无法保证强一致性,只能做到最终一致性。所以我们的目标是尽可能地做到一致,但底线是最终一致性

注意:以下的讨论都是基于Redis(集群)和MySQL(主从读写分离),讨论的点在于,线程在更新数据库时,对缓存应当作何操作。

我们假设数据更新前旧数据已经存入了缓存,由于底线是最终一致性所以在数据库更新之后,对缓存一定要有一个操作,至于这个操作是什么,我们接着看。

>>> 数据库更新后的操作

我们只要找出这些操作可能出险问题的场景,就可以对其进行推翻。

> 1. 缓存即时更新(不可取)

问题场景:

  1. 线程A执行DB更新
  2. 线程B执行DB更新
  3. 线程B执行缓存更新
  4. 线程A执行缓存更新

数据库最终结果是B,而缓存里留下的是A,所以即时更新操作不可取。

> 2. 缓存延时更新(不可取)

问题场景:

  1. 线程A执行DB更新,睡眠
  2. 线程B执行DB更新,睡眠
  3. 线程B执行缓存更新
  4. 线程A执行缓存更新

数据库最终结果是B,而缓存里留下的是A,所以延时更新操作不可取。

> 3. 缓存即时删除(不可取)

问题场景:

  1. 线程A执行DB更新
  2. 线程A执行缓存删除
  3. DB从节点更新A线程数据
  4. (DB主从之间网络波动)
  5. 线程B执行DB更新
  6. 线程B执行缓存删除
  7. 线程C读取缓存失败
  8. 线程C读取数据库从节点数据
  9. 线程C写入缓存数据
  10. DB从节点更新B线程数据

数据库最终结果是B,但缓存被设置为了A,所以即使删除不可取。

> 4. 缓存延时删除(可取)

将缓存删除操作延时几百毫秒后进行操作,可以有效防止上述的DB主从之间的常见同步问题(暂不讨论主从同步长时间失败的情况)。

有人会选择将此删除任务丢到线程池中,线程先睡一会再去执行,这个操作效率低,不推荐。可以考虑使用线程池里的延时队列(DelayedWorkQueue)。

考虑完了数据库更新完成之后的操作,现在来看,数据库更新之前的操作

>>> 数据库更新前的操作

其实这里的操作,都不会很完美,所以需要看业务的容忍度Tolerance

> 1. 缓存更新(个人不推荐)

个人不推荐,因为大多数业务场景都比较注重,落库为安,一个数据还没有成功写入,它就有可能是问题数据。宁愿向用户展示旧的正常数据,也不要让问题数据出现。

> 2. 不作操作(看情况选择)

如果你的业务场景对于旧数据的容忍度比较高,可以选择这种方式,虽然正确的缓存会在数据库更新后的几百毫秒之后才能更新(配合上述的延时删除策略),但是你可以选择不在乎。

毕竟,可以省下一次缓存删除和一次缓存写入的开销,对缓存比较友好。

> 3. 缓存删除(推荐)

它和不作操作相比,多一次缓存删除和一次缓存写入的开销。(绝大多数情况下,不在乎这样的开销)

在理想的情况下,缓存删除后,下次查询缓存的线程,会在数据库更新完之后进行调用,这是数据没有问题。(在并发量不大的情况下,容易达成)

但如果查询调用的比较频繁,那么容易出现,在数据库更新的事务提交之前,就进行了缓存的查询,数据库查询操作,然后缓存会写入旧数据,且在几百毫秒之后才会更新为新数据(同样配合上述的延时删除策略)。

所以它并不完美,但比较下来性价比不错,推荐。

>>> 小结

通过以上的阐述,基本可以确定,数据库更新前进行缓存删除,更新完成后进行延时删除是理智的选择,这其实也就是我们常说的延时双删

延伸:借助其他中间件
上面我们提到了,数据库更新后不能用更新缓存的方式,也不能用即时删除。
但是在借助Canal中间件(由阿里开源,原理是监听数据库主节点的binlog)以后,可以打破这些说法。
但代价是,项目复杂度大大增加。
至于它的具体用法,这里不作阐述,资料很多,可以自行查阅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值