Redis缓存问题(上)

139 阅读2分钟

大家好,我叫小贤。今天从极客时间上学些了Redis在业务使用中的缓存异常场景和解决思路,总结了以下文章,让我们从问题出发吧。

1. 使用缓存Redis怎么样才会产生数据不一致的现象?

2. 业务中使用缓存时,为什么要删除缓存而不是立即更新缓存呢?

3. 如何确保缓存实现(最终)一致?

Redis使用过程中,在业务侧一般要执行两步操作,操作(CTRL)数据库,再更新/删除缓存,因此不可避免有先后顺序,为了保证数据的一致性,因此会产生数据两边不一致的现象,先来看是怎么产生数据不一致的。

  一、并发现象

A、B两个线程,最后缓存成了旧值

场景一重现:

步骤1. A删缓存 

       2. B读缓存,读数据库 

       3. A更新数据库 

       4. B写缓存

场景二重现:

步骤1. A读不到缓存,读数据库 

       2. B更新数据库 

       3. B删除缓存 

       4. A写入缓存

二、第二步失败现象

场景一重现:

        先删除缓存再更新数据库,第二步如果失败:

        数据库旧值,查不到缓存就取到了旧值

场景二重现:

        先更新数据库再删除缓存,第二步如果失败:

        取到缓存的数据就是旧值

不管哪个现象的第二步失败,缓存的数据都会不对

三、更新缓存好还是删除缓存好?

并不是每个缓存都会马上用到,而且缓存的数据可能是计算得到的,还要花费时间去计算再去更新,还不如直接删除缓存,下次用到这个数据再去缓存

四、为什么要选择先更新数据库而不是先删除缓存?

如上并发时,场景二中,如果线程A先更新数据库,线程B如果取不到缓存,读数据库的值后,再写入缓存,这个线程B花费的时间肯定比线程A的要快(读数据库时间比写数据库时间短),所以理论上不会出现A写入缓存的时间在B删除缓存之后。因此选择先更新数据库而不是先删除缓存。

五、怎么保证两步都执行成功(最终一致性)

1、直接进行重试,或做补偿机制

2、异步重试,使用消息队列保证可靠性

3、订阅数据变更日志:

3.1 无需考虑写消息队列失败情况:只要写 MySQL 成功,Binlog 肯定会有;

3.2 自动投递到下游队列:canal 自动把数据库变更日志「投递」给下游的消息队列

读极客时间总结,链接如下:Redis课程

参考链接:缓存和数据库一致性问题

自己做的思维导图