面试官常拷打:如何下保证MySQL数据库与Redis缓存数据一致性?

作者:微信小助手

发布时间:2024-11-08T00:34:59

对于读多写少并且要求高性能的业务逻辑,我们通常在应用服务器访问MySQL数据库的中间加上一层Redis缓存层,以提高数据的查询效率,减轻MySQL数据库的压力,避免在MySQL出现性能瓶颈。

image-20240916023730395

该问题,如果在数据存储后,只读场景下是不会出现MySQL与Redis缓存的一致性问题的,所以真正需要考虑的是并发读写场景下的数据一致性问题。

如果我们不加分析,单独利用MySQL和Redis的知识进行回答并发场景下如何保证MySQL与Redis缓存一致性?很难把这个问题回答好,因为看起来很简单的方案实际上是漏洞百出的。

简单方案下的漏洞百出

我们先看下简单的更新数据库、删除缓存和更新缓存方案下,会出现什么问题?

image-20240915220902509

更新缓存,再更新数据库

先说结论:不考虑

原因是更新缓存成功后,数据库可能更新失败,出现数据库为旧值,缓存为新值。导致后续的所有的读请求,在缓存未过期或缓存未重新正确更新的情况下,会一直保持了数据的完全不一致!并且当前数据库中的值为旧值,而业务数据的正确性应该以数据库的为准。

那么如果更新缓存成功后,数据库可能更新失败,我们重新更新缓存是不是可以了?

image-20240916004707314

抛开需要重新更新缓存时,要单表或多表重新查询数据,再更新数据带来的性能问题,还可能期间有数据变更再次陷入脏数据的情况。实际上仍然还是会出现并发一致性问题。

只要缓存进行了更新,后续的读请求在更新数据库前更新数据库失败并准备更新缓存前,基本上都能命中缓存情况,而这时返回的数据都是未落库的脏数据。

image-20240916004728685

更新数据库,再更新缓存

不考虑。

原因是当数据库更新成功后,缓存更新失败,出现数据库为最新值,缓存为旧值。导致后续的所有的读请求,在缓存未过期或缓存未重新正确更新的情况下,会一直保持了数据的完全不一致!

image-20240916004758430

该方案就算在更新数据库、更新缓存都成功的情况下,还是会存在并发引发的一致性问题,如下图所示(点击图片查看大图):

image-20240916005545173

可以看到在并发多写多读的场景下数据存在的不一致性问题。

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

不考虑,但是通过使用延时双删策略后可以考虑。

采用“先删除缓存,再更新数据库”的方案是一种常见的方法来尝试解决这个问题的策略。

这种方法逻辑较为简单,易于理解和实现,理论上删除旧缓存后,下次读取时将从数据库获取最新数据。

但在并发的极端情况下,删除缓存成功后,如果再有大量的并发请求进来,那么便会直接请求到数据库中,对数据库造成巨大的压力。而且此方案还是可能会发生数据不一致性问�