如何保证Redis和数据库的一致性

在使用Redis中,我们都会遇到同样的问题,当一个请求要更新数据库时,Redis缓存显然也要被更新。我们必须要保证两者的一致性。
而数据库和Redis是两个不同的进程,很难保证两个进程更新都一定能完成,一旦其中一个失败,或延时过长,就可能导致两者数据不一致,因而导致程序出错。
因此保证两者一致性变了值得讨论的话题。

首先数据库和缓存显然都是要更新的,那么无非就是顺序问题,那么就是一下两种情况。

方案A 先更新数据库,再更新缓存

方案B 先更新缓存,再更新数据库

关于两者更新的顺序,显然只能选A不能选B。为什么呢?
数据库和缓存其实是类似主从的概念,我们要明白,缓存是跟着数据库变的。那么就没有道理缓存优先数据库做更新。先更新缓存不符合原则。
那么虽然不符合原则,他安不安全呢?
不安全,举个栗子:

1线程先更新缓存,还未更新数据库
2线程后更新缓存,还未更新数据库
2线程先更新数据库
1线程后更新数据库

此时,因为2线程后更新缓存,所以缓存是2线程的数据,因为1线程后更新数据库,所以数据库是1线程的数据。如此,导致数据不一致。
所以该方案是不可接受的。

那么A方案就是可靠的吗?不,A也不可靠,再举个栗子。

1线程先更新数据库,还未更新缓存
2线程后更新了数据库,还未更新缓存
2线程先先一步更新缓存
1线程后一步更新缓存

导致数据库是2线程的值,缓存是1线程的值。同样不满足一致性。也不可接受。

也就是说AB方案都不可接受
那么解决方案是什么呢?
更新数据时,删除缓存,这样查询就会去数据库取最新值。并更新到缓存。保证了缓存和数据库的最终一致
当然,操作的顺序也有两种。

方案C 先更新数据库,再删除缓存

方案D 先删除缓存,再更新数据库

我们之前也提到了,缓存和数据库的关系是主从关系。因此应该先更新数据库,再操作缓存。

所以,只能选C。

那么C方案是否可靠呢?
绝大多数情况是可靠的。一般使用这种方法就足够了。
也有一些特殊场景。

步骤

1线程更新数据库,还未删除缓存
2线程查询缓存,返回旧数据
1线程删除缓存

可以看出,数据库已经更新了,但2线程拿到的是旧数据。对此时来说数据不对,随后1线程删除了缓存。
虽然数据不对,但满足了数据的最终一致性。再次查询时获取的就是最新值。

还有一种最差的场景
缓存刚好失效时

1线程查询数据库,获得值
2线程更新数据库,还未删除缓存
2线程删除缓存
1线程将值保存至缓存

这种场景下依旧会破坏一致性。不过可能性较小。需要满足缓存刚好失效,且刚好在更新数据。且刚好满足上述步骤。

因此,一般情况下,C方案是可行的,除此之外,还需要考虑缓存删除失败的情况。

缓存删除失败

缓存删除失败就需要进行重试,重试的方法有多种。
这里建议可以使用MQ,将删除失败的消息放入队列中。写一个方法监听这个队列,当有消息进入时,重新删除缓存。

猜你喜欢

转载自blog.csdn.net/qq_42068856/article/details/125702954