notesArea/Redis/数据库和缓存不一致问题.md

数据库和缓存不一致问题

缓存不一致场景

先写数据库后更新缓存

Thread 1Thread 2
写数据库,值为 10
写数据库,值为 20
写缓存,值为 20
写缓存,值为 10

最终,数据库中的值为 20,缓存中为 10

先更新缓存后写数据库

Thread 1Thread 2
写缓存,值为 10
写缓存,值为 20
写数据库,值为 20
写数据库,值为 10

最终,数据库中的值为 10,缓存中为 20

先读缓存后更新数据库

Thread 1Thread 2
读缓存,值为空
读数据库,值为 10
更新缓存,值为 10写数据库,值为 20

最终,数据库中的值为 20,缓存中为 10

缓存不一致解决方案

常见的有三种方案:

  1. 先更新数据库,再删除缓存
  2. 延迟双删:先删除缓存,再更新数据库,再删除缓存
  3. cache-aside:更新数据库,基于 binlog 监听更新缓存

为什么删除缓存而不是更新缓存

上述三个方案中,1、2 方案都选择删除缓存而不更新,理由如下:

当然,删除缓存会存在 cache miss 的问题,这个问题严重点可能导致 缓存击穿

先写数据库还是先删除缓存

在确定删除缓存而不是更新缓存的前提下,我们紧接着需要思考的问题是,删除缓存和写数据库之间的顺序。

先删除缓存

先删除缓存再更新数据库有一个好处:如果更新数据库失败了,不会影响已有业务。因为即使缓存已经被删除了,当请求再次查询的时候,还是会把数据库中的数据更新到缓存中。

这种策略会在读写并发的时候遇到问题,考虑如下流程:

Thread 1Thread 2
删除缓存,值为 10
读取缓存,值为空
读取数据库,值为 10
修改数据库,值为 20
更新缓存,值为 10

会导致缓存和数据库不一致。

先写数据库

此策略的好处是,先写数据库能确保持久层数据的准确,能保证数据最终的可靠性和一致性。

此策略的问题是,如果缓存删除失败了,也会导致数据不一致的情况。那怎么解决呢?可以使用 延迟双删

如何选择

如果业务量不大,并发不高,可以选择 先写数据库,因为这种方案更简单。反之选择先删除缓存再更新数据库,通过引入延迟双删、分布式锁等机制,减少并发带来的问题。当然,这种方式的复杂的也更高。

大纲
文件