美文网首页程序员JAVA
「微服务」缓存、数据库双写一致性

「微服务」缓存、数据库双写一致性

作者: 厦门张明爽 | 来源:发表于2020-01-02 09:37 被阅读0次

    前言

    缓存由于高并发和高性能的特性,在当前的主流架构中基本上属于必须的其中一个高并发支撑模块。缓存在使用时,读流程基本保持一致的认知,不存在其他异议。流程如下:

    image

    缓存读流程

    但是,在写流程上,由于需要同时将数据写入数据库与缓存中,就一定涉及到缓存与数据库数据双写,数据一致性的问题。所以,在系统的设计上,需要考虑如何处理数据一致性问题。

    一般来说,在引入缓存机制的同时也牺牲了一定的一致性,缓存数据与数据库数据是允许在一定时间窗口之间内的非一致性。如果必须保持一致的话,那么缓存的引入基本上没有意义了。必须保证强一致的话,就只能使用读请求和写请求串行化,串到一个内存队列里去。但是它也会导致系统的吞吐量大幅度降低,用比正常情况下多几倍的机器去支撑线上的一个请求。

    常用双写模式解析

    #先更新数据库,再删除缓存(Cache Aside)

    Facebook使用的方式,也是推荐的使用方式。包括:

    • 失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中;* 命中:应用程序从cache中取数据,取到后返回;* 更新:先把数据存到数据库中,成功后,再让缓存失效;
    image

    采用CacheAside模式的问题在于,在读写线程同时并发,且满足

    1. 读线程读取缓存时,缓存正好失效
    2. 读线程读数据库数据
    3. 写线程更新数据库
    4. 写线程删除缓存
    5. 读线程将查询到的数据写入缓存

    以上所有查件时,在理论上来说,确实可能会产生脏数据。但是实际上出现的概念极低。

    image

    首先,需要满足读缓存时缓存失效,并且存在并发写。在实际上,数据库的写操作完比读操作慢得多,而且还需要锁表,而读操作必须在写操作前进入数据库操作,而又晚于写操作更新缓存,所有条件具备的概率太低,基本上忽略。

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

    image

    先更新数据库,再删除缓存区别只是切换了执行的顺序。但是,该方式会导致大概率的不一致性发生。

    1. 写线程更新数据,删除缓存
    2. 读线程查询缓存数据,发现没有缓存数据
    3. 读线程读数据库数据
    4. 写线程更新数据库
    5. 读线程将查询到的数据写入缓存
    image

    解决方案:采用双删机制。删除缓存 > 更新数据库 > 休眠一点时间 > 再次删除缓存。

    但是该方案不采纳。休眠时间无法评估,而且大大降低了系统吞吐。

    #先更新数据库,再更新缓存

    该方案是不能被采用的方案。

    image

    如上图所示,写线程A和线程B同时更新数据,但是线程B早于线程A更新缓存,导致数据不一致。

    除此之外,缓存数据可能是多纬度的计算数据而不仅仅只是单一的某个数据。如某缓存数据由A表,B表,C表多表数据计算而成,那么缓存的更新因素就非常多的,而且要更新缓存,需要额外的查询其他表数据。

    删除缓存是一种懒计算,在需要的时候才去重新计算。

    推荐使用模式

    在上述的模式中,推荐采用先更新数据库,再删除缓存(Cache Aside)模式。

    但是存在一个问题,如果删除缓存的时候失败了如何处理?

    在生产中,缓存的使用依赖于抽象缓存接口,根据允许的数据差异时间窗口和业务,采用的是针对实际缓存进行包装,提供删除重试机制,业务层不需要额外关注删除问题,避免了业务侵入。

    重试机制采用的是本地重试。 根据配置的重试上限进行重试,达到上限无法删除成功抛出异常到上层。上层业务决定是否回滚修改,继续向上抛出异常,然后业务调用者的重试机制重新尝试。还是忽略该失败。

    正常情况下,由于缓存本身影响的一致性导致数据一定存在一定时间窗口的差异。如果缓存在特定某一时刻无法删除,正常情况下不会影响业务,这是被允许的情况(缓存的数据必须有过期时间,而且时间不能太久,根据业务设置合理过期时长是非常重要的)。如果出现批量的失败,可能是缓存系统异常或者业务系统异常都会被监控系统探测到(监控系统很重要),此时已经不是某个业务或服务的问题,而是整个系统问题。

    当然,如果非要强制一定要执行成功,建议方案使用MQ进行异步化。

    image

    总结

    缓存的使用时双写是无法很好的保证一致性的,在使用缓存时就应该接受这一点,而不是强求一致性,导致系统或者业务变得非常复杂。

    相关文章

      网友评论

        本文标题:「微服务」缓存、数据库双写一致性

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