Redis之缓存一致性

前面的文章我们已经介绍过了缓存的三种异常(缓存击穿、缓存穿透和缓存雪崩)以及如何解决。这篇文章我们来讲解一下缓存一致性问题。

什么是缓存一致性问题?

一般情况下,Redis是用作应用程序和数据库之间读操作的缓存,主要目的是减少数据库的IO,还可以提升数据的IO性能。

当应用程序要去读取一个数据时,首先会尝试从Redis中读取,如果命中了就直接返回结果,如果没有命中,就从数据库中查询,查询到数据后再把这个数据缓存到Redis中并返回结果。

在这样的架构中,会出现一个问题,就是一份数据,同时保存在数据库和Redis中,当数据发生变化的时候,需要同时更新Redis和MySql,由于更新是有先后顺序的,这种两边写入的情况下,并不能像单纯数据库操作一样,可以满足ACID的特性。因此,就可能存在一方更新成功而另一方更新失败的情况,从而出现缓存和数据库中数据不一致的问题,也就是缓存一致性问题。

如何解决?

我们先将出现缓存一致性问题的场景进行分类,分别是先删除缓存,再更新数据库先更新数据库,再删除缓存两种场景。

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

先删除缓存,此时数据库还没有及时更新成功,此时如果有另一个线程来读取缓存中的值,由于缓存被删除,这条线程就会去数据库中进行读取,但是数据库此时还没有更新,所以读取到的还是旧值,缓存不一致问题就发生了。

解决方法------延时双删

延时双删的方案的思路是,为了避免更新数据库的时候,其他线程从缓存中读取不到数据,就在更新完数据库之后,再Sleep一段时间,然后再次删除缓存,具体的流程如下:

(1)线程1删除缓存,然后去更新数据库;

(2)线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取数据,这时候由于数据库还没有及时更新,所以读取到的还是旧值,然后把旧值写入了缓存;

(3)线程1,根据估算的时间来进行Sleep操作,Sleep醒来后,线程1再次删除缓存;

(4)如果此时还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值。

存在的问题

如何取Sleep的时间其实很难进行衡量,如果时间取的过短,很有可能数据库还没有更新的时候双删操作就完成了,缓存就会一直保持旧值;如果时间取的过长,就会导致更新后的缓存又被删除了,造成重复写入缓存。

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

如果将上面的场景反过来,这个产生的问题会更加明显,就是更新数据库的操作成功了,但是缓存删除操作失败了,或者没有来得及进行缓存删除操作,这个时候其他线程去访问缓存,拿到的还是原来的旧值,缓存一致性问题出现了。

解决方案------消息队列

先更新数据库,成功之后往消息队列中发送消息,消费到消息后再删除缓存,借助消息队列的重试机制来实现缓存的删除,最终达到数据的一致性。

存在的问题

(1)引入消息中间件之后,问题更加复杂了,怎么保证消息不丢失更加麻烦;

(2)就算不考虑消息丢失的问题,由于缓存的删除不是立即进行的,所以不能保证缓存一致性的高时效性,只能保证最终的缓存一致性。

进阶版的消息队列解决方案

为了解决缓存一致性的问题单独引入一个消息队列,太复杂了。其实,一般的大公司本身都会有监听binlong消息的消息队列存在,主要是为了做一些核对的工作。

可以借助监听binlog消息的消息队列来做删除缓存的操作。这样做的好处是,不用引入一个新的消息队列到业务代码中,同时保证了高可用。

当然问题还是上面提到的问题,不过在并发量不是特别高的场景下,这种做法的实时性和一致性都还算可以接受的。

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

就以先更新数据库,再删除缓存为例,如果不是删除缓存而是更新缓存的话,如果数据库在1个小时内更新了2000次,那么相对的缓存也要跟着更新2000次,但是在这1个小时内,缓存只被访问到了1次,那么这2000次的更新操作和1次的删除操作相比,显然是删除操作的性能更高一些。换句话说,缓存不需要实时更新,只有在用到缓存的时候在去数据库中读取新数据即可。

这篇文章我们讲解了Redis的缓存一致性问题和解决方案,大家有什么问题或者勘误的话可以在评论区留言,笔者看到都会回复的。

相关推荐
TDengine (老段)2 分钟前
TDengine 数学函数 ASIN() 用户手册
大数据·数据库·sql·物联网·时序数据库·tdengine·涛思数据
稚辉君.MCA_P8_Java7 小时前
JVM第二课:一文讲透运行时数据区
jvm·数据库·后端·容器
阳光明媚sunny8 小时前
Room持久化库中,@Transaction注解的正确使用场景是?
android·数据库
北极糊的狐8 小时前
MySQL常见报错分析及解决方案总结(15)---Can’t connect to MySQL server on ‘localhost‘ (10061)
数据库·mysql
濑户川9 小时前
Django5 与 Vue3 表单交互全解析:从基础到实战
数据库
weixin_438077499 小时前
langchain官网翻译:Build a Question/Answering system over SQL data
数据库·sql·langchain·agent·langgraph
-雷阵雨-10 小时前
MySQL——数据库操作攻略
数据库·mysql
krielwus10 小时前
Oracle ORA-01653 错误检查以及解决笔记
数据库·oracle
Wadli10 小时前
csdn| MySQL
数据库·mysql
程序员水自流10 小时前
MySQL InnoDB存储引擎关键核心特性详细介绍
java·数据库·mysql