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的缓存一致性问题和解决方案,大家有什么问题或者勘误的话可以在评论区留言,笔者看到都会回复的。

相关推荐
将心ONE5 分钟前
subprocess.check_output和stdout有什么不同 还有run和popen
java·数据库·microsoft
isNotNullX1 小时前
据字典是什么?和数据库、数据仓库有什么关系?
大数据·数据库·数据仓库·oracle·数据治理
考虑考虑1 小时前
数据库唯一索引
数据库·后端·mysql
AA-代码批发V哥1 小时前
MySQL之事务深度解析
数据库·mysql
里探2 小时前
在Django中把Base64字符串保存为ImageField
数据库·django
全栈小52 小时前
【数据库】零门槛在线体验KingbaseES平台,SQL Server模式高阶玩法,动态创建数据体验函数、存储过程等功能
数据库·sql server·金仓·kingbasees平台
奈斯ing3 小时前
【MySQL篇】高效学习官方文档指南(基于MySQL8.0版本详解)
运维·数据库·学习·mysql
Brandon汐4 小时前
数据库part2---子查询
数据库·sql
Tapdata 钛铂数据4 小时前
信创 CDC 实战|国产数据库的数据高速通道:OceanBase 实时入仓 StarRocks
数据库·oceanbase
liyongjie4 小时前
openGauss数据库DWR报告解读
数据库·oracle