一文总结缓存与数据一致性问题

缓存与数据一致性

先看一个大概的流程图

根据以上的流程没有问题,但是当数据变更的时候,如何把缓存变到最新,使我们下面要讨论的问题。

1.更新了缓存,再更新数据库

假设数据库更新成功,缓存更新失败,在缓存失效和过期的时候,读取到的都是老数据缓存。

2.更新了数据库,再更新缓存

缓存更新成功了,数据库更新失败,是不是读取的缓存的都是错误的

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

有一定的使用量。即使数据库更新失败。缓存也可以会刷。

在高并发的场景下,存在的问题是什么?

假设A请求删除了缓存数据,B请求来获取数据,查询不到数据时,认为是数据过期了,直接拿数据库内的数据并且填充到缓存了。这时A请求才去更新数据库,而缓存数据已经被B拿旧数据填充了。这样缓存和数据库就不是一致的了。

可以采用延迟双删的策略,应对这个高并发下出现的问题,那什么是延迟双删呢?

这里指的是删除两次缓存,首先删除缓存,然后更新数据库,为了避免有其他的请求拿错误的数据覆盖到了缓存,再次删除掉缓存,让下一次的请求命中到数据库,从而把最新的数据填充到缓存。

为什么会存在延迟双删呢,普通的双删时,假设B请求获取到了旧数据,准备填充到缓存,A请求刚刚更新完数据库,立刻删除了缓存,在删除完成后B请求才把旧数据去填充,这样依然会出现缓存与数据库不一致的情况(即缓存内数据错误)。

延迟双删就是A请求更新完数据库之后,延迟那么一会再去删除缓存,这样的目的也很明显,就是为了让B请求(以及其他很多相近时间的请求)已经拿旧数据填充过缓存了,并且已经走完这一段逻辑了,后续不会去尝试覆盖缓存了。这个时候再去删除缓存,下一次去填充缓存的时候就拿到的是A请求更新好的正确的数据了。

4.先更新数据库,再更新缓存

假设A请求更新了数据库,还未情况缓存的情况下,B请求拿到的是缓存内的旧数据,因为A还没来得及把新的数据填充到缓存。

存在的问题就是:会有一段时间存在缓存滞后的问题,但是在没有实时一致性那么强要求的场景是最好的方案了

但是这里还有问题,在更新数据库后,想要去更新缓存的时候,因为一些未知的问题,导致缓存没有更新成功,这个情况怎么办?缓存里面就会一直是旧数据。具体看一下第五点讲一下拓展思路

5.扩展思路

第四点的缓存更新失败了,导致缓存与数据不一致,我们想要应对这种问题

我称这种问题叫如何保证缓存与数据的最终一致性?

  • 引入消息队列做补偿进行兜底

    删除失败的缓存,作为消息打入 mq,mq 消费者进行监听,再次进行重试刷缓存。

  • 阿里开源的cannal

    监听数据库的变化,做一个公共服务,专门来对接缓存刷新。优点业务解耦,业务太多冗余代码复杂度。

    canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送 dump 协议,其实就是 MySQL 的主从复制的原理

相关推荐
Piper蛋窝1 分钟前
Go 1.15 相比 Go 1.14 有哪些值得注意的改动?
后端
用户35391699362153 分钟前
DeepSeek回答过于笼统,提示词如何优化
程序员
K8sCat8 分钟前
Golang与Kafka的五大核心设计模式
后端·kafka·go
小希爸爸18 分钟前
3、中医基础入门和养生
前端·javascript·后端
摆烂工程师35 分钟前
ChatGPT免费用户可以使用Deep Research啦!并且o3、o4-mini的可使用次数翻倍!
前端·后端·程序员
_一条咸鱼_39 分钟前
揭秘 Android ListView:从源码深度剖析其使用原理
android·面试·android jetpack
_一条咸鱼_40 分钟前
深入剖析 Android NestedScrollView 使用原理
android·面试·android jetpack
_一条咸鱼_40 分钟前
揭秘 Android ScrollView:深入剖析其使用原理与源码奥秘
android·面试·android jetpack
_一条咸鱼_41 分钟前
深入剖析 Android View:从源码探寻使用原理
android·面试·android jetpack
_一条咸鱼_41 分钟前
揭秘 Android View 绘制原理:从源码剖析到极致理解
android·面试·android jetpack