绝!面试官还是张嘴问了缓存一致性

80 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

缓存是如何使用的

一般而言,缓存是因为系统之间,不同的介质访问速度不一样才存在的。例如CPU中的多级缓存,所以缓存的特性大抵都是访问快,容量小。由此,Redis根据缓存的作用可以分为两种类型:只读缓存,读写缓存

只读缓存

先聊聊只读缓存,这也是缓存的日常使用方式。为了提速应用服务的查询请求、缓解MySQL等业务数据库的压力,如下图:

Redis使用流程-2.png

首先,只读缓存下有两种业务操作

更新操作:业务系统更改数据,①删除缓存里面的值,②直接操作修改数据库,③应用返回更新成功。

查询操作:业务系统查询数据,①从缓存里面查数据,②如果没有查到,则出现缓存缺失,去数据库里面查,③应用程序从数据库拿到值之后再写会Redis里,返回查询到的数据。

读写缓存

读写缓存是将缓存作为业务数据库使用,最新数据是在Redis里面的。正如你担忧的那样,Redis是内存数据,数据的安全性会由于服务的不可用而发生数据丢失,从而有着业务风险。

Redis读写缓存使用流程.png

如图,展示了读写缓存的流程,我们可以看到业务数据的修改直接放在了缓存里,而数据的持久化更多的是根据数据的安全性、请求的响应速度来评估是同步直写还是异步写回

在生产实践中,我们根据不同的场景来选择不同的缓存使用方式。

缓存不一致

之所以要先聊缓存在使用上的区别,是因为不同的使用方式,造成的缓存不一致处理方式也不一样。首先,我们先定义一下,什么是缓存一致。

缓存一致:①缓存中有数据,缓存和数据库一致,才是一致②缓存中没有,数据中是最新的数据,才是一致的。

读写缓存的一致性:如我们上面聊得缓存策略,读写缓存要保证数据一致,必须采用同步直写的方式,通过业务系统来保证Redis和MySQL的分布事务,从而是的数据的更新保证原子性。

只读缓存的一致性,情况比较复杂,可以看一看上面的只读缓存的流程。

操作顺序问题
先删除缓存,再更新数据库如果数据库更新时间较长,再次访问,缓存缺失,从数据库读取旧值,数据不一致
先更新数据库,再删除缓存删除缓存失败或者在改数据库值间隙,访问时候缓存命中旧值,数据不一致

那么我们依次进行讨论:

不一致情况一:先删缓存,再更新数据库

时间线程A线程B出现状况
t1删除缓存
t21、读取缓存,缓存缺失,从数据库load出旧值
2、数据写入缓存
由于线程B的操作,其他线程可能会读到旧值
t3更新数据库缓存和数据库不一致

对于此类情况下造成的数据不一致,我们可以采用延迟双删的策略。也就是我们再更新完成之后,再删除一次。

时间线程A线程B出现状况
t1删除缓存
t21、读取缓存,缓存缺失,从数据库load出旧值
2、数据写入缓存
由于线程B的操作,其他线程可能会读到旧值
t3更新数据库
t4sleep等待一下其他读了旧值的线程,返回
t5删除缓存缓存中没有值,数据库中是最新值,数据一致

不一致情况二:先更新数据库,再删除缓存

时间线程A线程B出现状况
t1更新数据库
t21、读取缓存,缓存命中,读到旧值线程A尚删除缓存,并发请求读到旧值
t3删除缓存

在这种情况下,由于删除缓存的操作较为快速,如果再线程并发不高的情况下,对业务的影响比较小。

总结

对于缓存不一致的解决方案,思路大概是这样,总体来说,我们需要根据我们业务特性、缓存使用方式来应对不同的情况。如果你有任何问题,欢迎与我交流。