zoukankan      html  css  js  c++  java
  • 缓存与数据库的一致性思考

    https://www.cnblogs.com/johnsblog/p/6426287.html

    问题:怎么保持缓存与数据库一致?

    要解答这个问题,我们首先来看不一致的几种情况。我将不一致分为三种情况:

    1. 数据库有数据,缓存没有数据;

    2. 数据库有数据,缓存也有数据,数据不相等;

    3. 数据库没有数据,缓存有数据。

    在讨论这三种情况之前,先说明一下我使用缓存的策略,也是大多数人使用的策略,叫做 Cache Aside Pattern。酷壳里的 缓存更新的套路 一文,很值得一读,我的策略也是从他那学来的。

    简而言之,就是

    1. 首先尝试从缓存读取,读到数据则直接返回;如果读不到,就读数据库,并将数据会写到缓存,并返回。

    2. 需要更新数据时,先更新数据库,然后把缓存里对应的数据失效掉(删掉)。

    读的逻辑大家都很容易理解,谈谈更新。如果不采取我提到的这种更新方法,你还能想到什么更新方法呢?大概会是:先删除缓存,然后再更新数据库。这么做引发的问题是,如果A,B两个线程同时要更新数据,并且A,B已经都做完了删除缓存这一步,接下来,A先更新了数据库,C线程读取数据,由于缓存没有,则查数据库,并把A更新的数据,写入了缓存,最后B更新数据库。那么缓存和数据库的值就不一致了。

    另外有人会问,如果采用你提到的方法,为什么最后是把缓存的数据删掉,而不是把更新的数据写到缓存里。这么做引发的问题是,如果A,B两个线程同时做数据更新,A先更新了数据库,B后更新数据库,则此时数据库里存的是B的数据。而更新缓存的时候,是B先更新了缓存,而A后更新了缓存,则缓存里是A的数据。这样缓存和数据库的数据也不一致。

    按照我提到的这种更新缓存的策略,理论上也是有不一致的风险的,酷壳的文章有提到,只不过概率很小,我们暂时可以不考虑,后面我们有其他手段来补救。

    讨论完使用缓存的策略,我们再来看这三种不一致的情况。

    1. 对于第一种,在读数据的时候,会自动把数据库的数据写到缓存,因此不一致自动消除

    2. 对于第二种,数据最终变成了不相等,但他们之前在某一个时间点一定是相等的(不管你使用懒加载还是预加载的方式,在缓存加载的那一刻,它一定和数据库一致)。这种不一致,一定是由于你更新数据所引发的。前面我们讲了更新数据的策略,先更新数据库,然后删除缓存。因此,不一致的原因,一定是数据库更新了,但是删除缓存失败了。

    3. 对于第三种,情况和第二种类似,你把数据库的数据删了,但是删除缓存的时候失败了。

    因此,最终的结论是,需要解决的不一致,产生的原因是更新数据库成功,但是删除缓存失败。

    我想出的解决方案大概有以下几种:

    1. 对删除缓存进行重试,数据的一致性要求越高,我越是重试得快。

    2. 定期全量更新,简单地说,就是我定期把缓存全部清掉,然后再全量加载。

    3. 给所有的缓存一个失效期。

    第三种方案可以说是一个大杀器,任何不一致,都可以靠失效期解决,失效期越短,数据一致性越高。但是失效期越短,查数据库就会越频繁。因此失效期应该根据业务来定。

  • 相关阅读:
    时间控件My97DatePicker,实现时间的选择,具体运用
    OnClientClick事件和验证控件同时用的时候,会有问题
    根据Eval()函数绑定的值,来显示GridView中的控件的方法
    打印部分页面内容(Javascript)
    U盘装系统中bios怎么设置USB启动(图文教程)
    TextBox控件只允许输入数字(转)
    JS模态窗体的运用,以及相关注意事项(有用到window.returnValue)
    控件TextBox与验证控件相结合产生的控件(运用)
    linq 实现动态 orderby(根据参数名排序)
    yii 多个数据库链接
  • 原文地址:https://www.cnblogs.com/newlangwen/p/9989025.html
Copyright © 2011-2022 走看看