缓存我们都接触过了很多,它是数据交换的缓冲区,可以临时存储数据,一般读写性能都是很好的。

而今天我们就来聊一聊redis缓存和数据库如何保持数据的一致性。

图片

正常情况下,用户的请求会先访问redis缓存,若缓存命中,则直接将缓存的数据返回给用户,若未命中,redis会将请求转发至数据库(mysql),再由数据库返回数据给用户。

增加了redis缓存之后,在很大程度上减少了数据库的压力;但是也给系统维护带来了一个很大的问题——如何保证缓存和数据库的一致性?

我们的数据不是一成不变的,在更新数据之前,我们需要先考虑一个问题:到底是先更新缓存,还是先更新数据库? 这两种做法有什么区别,对用户请求的影响如何?

Q1: 先更新缓存还是先更新数据库?

可能有些小伙伴们考虑得不够深入的会认为这两种策略都是没什么太大问题的,确实如果是“请求轮流访问”的话,问题不大;但是如何放在高并发的场景下考虑的话,就可能产生大问题了。

请看图:

图片

(先更新缓存)

结合上图我们很容易就发现先更改缓存的问题所在,请求1要将数据修改为1,请求2要将数据修改为2,在并发场景下存在以上情况,最终导致了缓存和数据库不一致(缓存中数据为2,而数据库数据为1)

有了以上的例子之后,相信各位聪明的朋友们很快就可以想到先更改数据库的问题了——缓存中数据为1,而数据库为2。

总结:以上两种策略都可能引发缓存和数据库数据不一致的问题!

那既然这样子,能不能有新的方法呢?

这时候应该会有朋友提出“不是更新缓存,而是删除缓存”的想法:删除了缓存,再由请求到来时构建,这样子第一次的缓存数据是直接来源于数据库的应该就不存在不一致的问题了吧?

其实不然,请看图:

图片
(先删缓存,再更新数据库)

由上图,我们可以知道当两个线程(一个是更新线程,另一个是读进程)时,有可能发生不一致的情况。

同样的,“先更新数据库,再删除缓存”也同样存在类似的问题,见下图:

图片

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

总结:

1.删除缓存还是更新缓存?

更新缓存:每次更新数据库都更新缓存,无效写操作较多(每次修改时都需要更新缓存,如果前面n次都是错误的修改,最后一次才是所需要的修改,则多做了n次无用功)。

删除缓存:更新数据库时让缓存失效,查询时再更新缓存

2.如何保证缓存与数据库的操作的同时成功或失败(操作的原子性)?

单体系统,将缓存与数据库操作放在一个事务,由事务的原子性进行保证同时成功。

分布式系统,利用TCC等分布式事务方案。

3.先操作缓存还是先操作数据库?

先删除缓存,再操作数据库

先操作数据库,再删除缓存

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐