缓存一致性?get

简介: 缓存一致性?get

       

大家好,我是老三,今天又是被算法致郁的一天,写篇文章缓一缓。

这篇文章,我们来看看缓存一致性问题。

缓存一致性

我接下来会巴巴说一堆缓存一致性,但是——

作为一名暴躁老哥,我先把结论撂这了!

缓存和数据库的强一致性无法实现!

CAP理论了解一下,缓存适用的场景属于CAP中的AP,是非强一致性的场景。

那还扯个犊子的缓存一致性?洗洗睡吧。

BASE理论接着了解一下,强一致性保证不了,那只好委屈求全,尽量保证最终一致性呗。

最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

所以,我们追求的是尽可能保证缓存和数据库的最终一致性。

image.png

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

Cache Aside Pattern

在开始之前,我们先来科普一下缓存+数据库读写,最经典的Cache Aside Pattern。

  • 读取:先读取缓存,缓存里没有,读取数据库,然后返回响应,顺斌保存缓存

image.png

  • 更新:先更新数据库,然后删除缓存

image.png

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

  • 并发情况下更新缓存可能会带来种种问题,直接删除缓存更加稳妥。
  • 缓存更新在很多时候需要耗费资源,直接删除,用时再从数据库读取,写进缓存,更省性能。

一致性问题

那么我们采用这种先更新数据库,再删除缓存,可能会出现什么问题呢?

假如,我们更新数据库成功,接下来还没来删除缓存,或者删除缓存失败怎么办?

那么很明显,这时候其它线程进来读的就是脏数据。

image.png

那怎么解决呢?

解决方案

既然删除缓存失败会导致脏数据,那我们就想办法让它能删除成功呗。

消息队列重试机制

我们可以引入一个重试机制。

如果删除缓存失败,向消息队列发送消息,把删除失败的key放进去,消费消息队列,获取要删除的key,然后去重试删除。

但是,这么干,好好的业务,咱们又引入了消息队列,对现有的业务造成了入侵,复杂度又提升了。

监听binlog异步删除

其实还有另外一种办法,我们可以用一个服务(比如阿里的 canal)去监听数据库的binlog,获取需要操作的数据。

然后用另外一个服务获取订阅程序传来的信息,进行缓存删除操作。

image.png

这样一来,对我们本身的业务入侵就小了很多。

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

一致性问题

我们看一下,如果先删除缓存,再更新数据库可能会带来什么问题。

在并发情况下,先删除缓存,再更新数据库,此时数据库还未更新成功,这时候有其它线程进来了,读取缓存,缓存不存在,读取数据库,读取的是旧值,这时候,缓存不一致就发生了。

image.png

解决方案

延时双删

延时双删是什么意思呢?

就是在删除缓存,更新数据库之后,休眠一段时间后,再次删除缓存。

image.png

延时删除之后,就把缓存里缓存的旧值给删除了。

再有请求进来,就是读取数据库里的新值,再把新值保存进缓存。

当然,第二次删除也有失败的可能,怎么办呢?重试。那怎么重试呢?前面写了。

关于删除,还有一个兜底的方案——设置缓存过期时间,这样一来,哪怕缓存了脏数据,但是脏数据总有过期的时候,不至于一直不一致。

总结

我们来简单总结一下,首先对缓存的操作,删除优于更新,所以要删除,而不是更新。

删除缓存两种方式:

  • 先更新数据库,在删除缓存。缓存不一致的两种处理方式是消息队列重试机制binlog异步删除
  • 先删除缓存,再更新数据库。缓存不一致的处理方式是延时双删

当然,这些方案无疑都增加了系统的复杂度。

如果不是并发特别高的话,就没有必要过度设计。

简单的事情重复做,重复的事情认真做,认真的事情有创造性地做。

我是三分恶,一个努力学习中的程序员。

点赞关注不迷路,咱们下期见!


目录
相关文章
|
2月前
|
缓存 NoSQL Java
面试官:如何保证本地缓存的一致性?
面试官:如何保证本地缓存的一致性?
382 1
|
18天前
|
缓存 索引
cpu缓存一致性问题---cache写策略
cpu缓存一致性问题---cache写策略
10 1
|
9天前
|
缓存 NoSQL Java
Spring Boot与Redis的缓存一致性问题
Spring Boot与Redis的缓存一致性问题
|
11天前
|
消息中间件 缓存 安全
并发中如何保证缓存DB双写一致性(JAVA栗子)
并发中如何保证缓存DB双写一致性(JAVA栗子)
|
2月前
|
消息中间件 缓存 中间件
中间件缓存一致性
【5月更文挑战第6天】中间件缓存一致性
27 1
中间件缓存一致性
|
1月前
|
canal 缓存 关系型数据库
高并发场景下,6种方案,保证缓存和数据库的最终一致性!
在解决缓存一致性的过程中,有多种途径可以保证缓存的最终一致性,应该根据场景来设计合适的方案,读多写少的场景下,可以选择采用“Cache-Aside结合消费数据库日志做补偿”的方案,写多的场景下,可以选择采用“Write-Through结合分布式锁”的方案,写多的极端场景下,可以选择采用“Write-Behind”的方案。
141 0
|
2月前
|
canal 缓存 NoSQL
【后端面经】【缓存】33|缓存模式:缓存模式能不能解决缓存一致性问题?-03 Refresh Ahead + SingleFlight + 删除缓存 + 延迟双删
【5月更文挑战第11天】Refresh Ahead模式通过CDC异步刷新缓存,但面临缓存一致性问题,可借鉴Write Back策略解决。SingleFlight限制并发加载,减少数据库压力,适合热点数据。删除缓存模式在更新数据库后删除缓存,一致性问题源于读写线程冲突。延迟双删模式两次删除,理论上减少不一致,但可能降低缓存命中率。选用模式需权衡优劣,延迟双删在低并发下较优。装饰器模式可用于实现多种缓存模式,无侵入地增强现有缓存系统。
69 2
|
2月前
|
缓存 数据库 NoSQL
【后端面经】【缓存】33|缓存模式:缓存模式能不能解决缓存一致性问题?-02 Write Through + Write Back
【5月更文挑战第10天】`Write Through`是一种缓存策略,写操作仅需写入缓存,缓存负责更新数据库。异步版本可能丢失数据,而同步变种先写数据库再异步刷新缓存,减少丢数据风险。`Write Back`模式数据先写入缓存,过期时才写入数据库,可能导致数据丢失,但若使用Redis并确保高可用,可部分解决一致性问题。在特定条件下,如使用SETNX命令,能缓解一致性挑战。
30 0
【后端面经】【缓存】33|缓存模式:缓存模式能不能解决缓存一致性问题?-02 Write Through + Write Back
|
2月前
|
缓存 网络协议 算法
Golang简单实现 分布式缓存+一致性哈希+节点再平衡(gossip + consistent + rebalance)
Golang简单实现 分布式缓存+一致性哈希+节点再平衡(gossip + consistent + rebalance)
103 0
|
2月前
|
缓存 NoSQL Redis
深度解析Redis的缓存双写一致性
【4月更文挑战第20天】
105 1