zoukankan      html  css  js  c++  java
  • 缓存一致性?get💡

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

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

    缓存一致性

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

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

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

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

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

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

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

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

    CAP和BASE理论

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

    Cache Aside Pattern

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

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

    读取

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

    更新

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

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

    一致性问题

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

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

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

    先更数据库,后删缓存问题

    那怎么解决呢?

    解决方案

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

    消息队列重试机制

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

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

    引入消息队列重试

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

    监听binlog异步删除

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

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

    监听binlog异步删除

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

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

    一致性问题

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

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

    先删缓存,后更数据库不一致

    解决方案

    延时双删

    延时双删是什么意思呢?

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

    延时双删

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

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

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

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

    总结

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

    删除缓存两种方式:

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

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

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

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

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

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



    参考:

    [1]. 缓存与数据库一致性问题深度剖析

    [2]. 数据库和缓存一致性的几种实现方式,我们来聊聊?

    [3]. 面试官:缓存一致性问题怎么解决?

    [4]. 美团二面:Redis与MySQL双写一致性如何保证?

  • 相关阅读:
    编译错误error: invalid&nbsp…
    移植OK6410'S dm9000ae…
    JavaScript 正则表达式-严格匹配
    JavaScript indexOf() 方法
    JavaScript splice() 方法
    Css文字效果
    知识点-语句
    知识点—变量、运算符(表达式)
    WPF RichTextBox相关总结
    WPF调用图片路径,或资源图片
  • 原文地址:https://www.cnblogs.com/three-fighter/p/15277139.html
Copyright © 2011-2022 走看看