美文网首页MySQL
数据库-缓存数据一致性问题

数据库-缓存数据一致性问题

作者: zhglance | 来源:发表于2019-06-24 20:38 被阅读45次

    一、问题描述:

    当使用DB + cache的架构时,会出现是先更新cache,还是先更新DB的问题。

    1.先更新cache,再更新DB:

    如果更新cache成功,但是更新DB失败,会导致cache和DB数据的不一致。业务在查询时,查询到的cache数据是更新后的,当cache过期后,经过一次miss,将查询到DB的脏数据。

    2.先更新DB,再更新cache:

    如果更新DB成功,但是更新cache失败,同样会导致cache和DB数据的不一致。业务在查询时,查询到的cache数据是更新前的脏数据,当cache过期后,经过一次miss,查询到的数据才是正确的数据。
    在多线程环境下,假如执行顺序如下:
    1.线程A更新DB;
    2.然后线程B更新DB;
    3.然后线程B更新cache;
    4.线程A更新cache。
    这样也导致了cache和DB数据的不一致。

    二、先淘汰缓存,再更新DB

    针对上述问题,有人提出淘汰缓存的策略,具体方法如下:
    1.先淘汰cache,如果成功,则更新DB;如果失败则不更新DB,后续可以通过重试来解决失败的问题,但是增加了一次cache的miss。

    淘汰策略解决了更新cache的数据一致性问题,但是增加了一次miss cache,淘汰缓存策略特别时候cache和DB数据格式不一样的场景,如cache中的数据是通过DB中的数据计算获得的(如组织架构的树形结构cache,避免对DB的递归查询,需要根据DB计算cache的数据结构),这样也节省了更新缓存的代价。

    2.1 并发导致先淘汰缓存的数据不一致性

    1.线程A执行数据更新操作,先淘汰cache;
    2.线程B执行查询操作,出现了miss cache;
    3.线程B查询DB,并将查询到的数据缓存到cache中;
    4.线程A此时更新DB。
    这样cache的数据和DB的数据出现了不一致,即此时cache保存的是脏数据。

    2.2 解决方案一:数据更新queue

    针对高并发时cache和DB不一致的问题,可以通过数据更新queue来实现,当要更新数据时,先将要更新的数据key保存到queue中,表示此时数据正在更新,当淘汰cache,执行DB都成功后,将数据从queue队列中删除key。

    在数据更新的过程中,先查看cache中是否有对应的key,如果有则返回数据;如果没有数据,则先去queue中查询是否存在对应的key,如果存在则使用while(true)来循环查询cache,并设置超时时间;如果queue中没有对应的key,则判断为miss cache,则读取DB,并将数据缓存到cache中,避免了高并发场景下的数据不一致性。

    以上方案也可以解决DB主从延迟的数据一致性问题,即当key在queue中时,程序读取主库,否则读取从库。

    2.3 解决方案二:延时双删除策略

    采用延时双删除策略,数据更新时具体过程如下:
    1.淘汰缓存;
    2.更新DB;
    3.sleep(100);
    4.再次淘汰缓存,避免因为另外线程读取时miss cache导致的脏数据保存到了cache。
    但是这种方案有sleep时间难以确定,而且加入步骤4再次淘汰执行失败,也同样导致cache和DB数据的不一致,不过可以通过缓存失效时间来实现最终一致性。

    三、先更新DB,再删除cache,即缓存旁路模式(Cache Aside Pattern )

    具体操作如下:

    1.数据查询

    先从cache中获取数据,没有得到,则从DB中获取,成功后将数据放到cache中。

    2.数据更新

    先更新DB,如果成功,则再执行淘汰缓存,如果执行淘汰缓存失败,则DB回滚。

    a.如果数据更新时,淘汰cache失败而不执行DB回滚,可以通过如下方案解决:

    方案一:使用MQ保存失败的key

    可以通过消息MQ来实现重试,即将淘汰cache失败的key发送到MQ中,然后消费MQ,执行淘汰cache操作,直到淘汰成功。

    方案二:使用数据库的binlog

    订阅DB的binlog,获取binlog中的数据的key,然后执行淘汰cache中的key,如果失败,则发送key到MQ,后续同方案一。

    b.多线程导致的不一致性

    线程A执行查询,线程B执行更新,具体过程如下:
    1.缓存过期失效;
    2.线程A查询,则会miss cache,线程A查询DB得到旧数据,然后准备执行更新cache;
    3.线程B更新数据,执行更新DB;
    4.线程B淘汰cache;
    5.线程A此时执行将旧数据更新cache;

    这样会出现数据不一致的情况,但该不一致性出现的条件是,步骤3写入DB操作比步骤2耗时更短,才会出现步骤4先于步骤5。而由于DB的读操作远快于写操作,所以上述场景出现的概率还是很小的。如果这样的概率仍然不可接受,则可以使用“延时双删除策略”双保险策略。

    相关文章

      网友评论

        本文标题:数据库-缓存数据一致性问题

        本文链接:https://www.haomeiwen.com/subject/hsdaqctx.html