• 如何保证缓存与数据库的双写一致性?


    1、传统的缓存使用方式为:

    ​ 读的时候,先读缓存,缓存中没有数据的话,就读数据库,然后将数据取出,存入缓存并返回。更新数据时,先将数据更新数据库,然后在删除缓存。

    2、为什么是删除缓存而不是更新缓存:

    ​ 在现实场景下缓存的数据不仅仅是数据库直接读取出来的值,可能需要和数据库中其他数据聚合,再次聚合计算后写入缓存的话,加大了性能消耗。

    ​ 其实删除缓存是一个Lazy计算的思想。

    3、初级的不一致问题及解决方案:

    ​ 问题:更新数据库后,删除缓存出错,导致数据库是新数据缓存中是旧数据。

    ​ 处理方式:先删除缓存,再更新数据库。

    ​ 如果删除缓存出错,数据库不会修改,两者都是旧数据;如果更新数据库出错,读取时,缓存中是空的,数据库是旧的,那么两者都是旧数据,可解决不一致问题。

    4、较复杂的不一致问题及解决方案:

    ​ 问题:数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改。一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中。随后数据变更的程序完成了数据库的修改,导致数据库是新数据缓存中是旧数据。

    ​ 处理方式:更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个 jvm 内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新读取数据+更新缓存的操作,根据唯一标识路由之后,也发送同一个 jvm 内部队列中。

    ​ 一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条一条的执行。这样的话,一个数据变更的操作,先删除缓存,然后再去更新数据库,但是还没完成更新。此时如果一个读请求过来,读到了空的缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成。

    ​ 这里有一个优化点,一个队列中,其实多个更新缓存请求串在一起是没意义的,因此可以做过滤,如果发现队列中已经有一个更新缓存的请求了,那么就不用再放个更新请求操作进去了,直接等待前面的更新操作请求完成即可。

    ​ 待那个队列对应的工作线程完成了上一个操作的数据库的修改之后,才会去执行下一个操作,也就是缓存更新的操作,此时会从数据库中读取最新的值,然后写入缓存中。

    ​ 如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回;如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值。

  • 相关阅读:
    MySQL字符串相加函数如何运行?似曾相识还是记一笔吧
    JQuery使用getJSON跨域调用数据
    匹配中文字符的正则表达式
    php中删除超链接的正则表达式
    win2003系统+IIS6下,经常出现w3wp.exe和sqlserver.exe的内存占用居高不下
    如何添加修改uchome创始人
    JS中Null与Undefined的区别
    错误分析及解决办法MySQL server has gone away
    更改表自动递增值的sql
    mysql如何修改导入数据库文件大小限制
  • 原文地址:https://www.cnblogs.com/dyaqi/p/15961063.html
Copyright © 2020-2023  润新知