1. 先更新数据库,再更新缓存

问题:(1)线程A写操作先更新数据库

           (2) 线程B写操作也更新数据库

            (3)当线程B比线程A先更新缓存(线程A停滞卡顿)

            (4)线程A最后更新缓存

 a,导致redis缓存与数据库不一致,出现脏数据

b,频繁更新,浪费性能

 2.先删缓存,再更新数据库

1,A,B两个线程同时要更新数据,并且A,B已经都做完了删除缓存这一步,A先更新数据库,C线程读取数据,由于缓存没有,则查数据库,并把A更新的数据,写入了缓存,最后B更新数据库。那么缓存和数据库的值不一致

2,   (1)请求A进行写操作,删除缓存
        (2)请求B查询发现缓存不存在
        (3)请求B去数据库查询得到旧值
        (4)请求B将旧值写入缓存
        (5)请求A将新值写入数据库

    延时双删+设置超时时间

(1)先淘汰缓存
(2)再写数据库
(3)休眠1秒,再次淘汰缓存

 伪代码:

public void write(String key,Object data){
        redis.delKey(key);

        db.updateData(data);

        Thread.sleep(1000);

        redis.delKey(key);

    }

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

旁路缓存策略(Cache Aside Pattern)

流程:

  1. 首先从缓存中查询数据,如果缓存命中则直接返回。

  2. 缓存未命中,则去数据库中读取。

  3. 将从数据库中读取的结果的副本放入到缓存中,并返回。

  4. 写操作

    流程:

    1. 首先更新数据库。
    2. 然后删除缓存中的数据

问题:(1)缓存刚好失效
           (2)请求A查询数据库,得一个旧值
           (3)请求B将新值写入数据库
           (4)请求B删除缓存
           (5)请求A将查到的旧值写入缓存

 但 读操作比写操作耗时更少,上述情况出现概率极低

使用Cache-Aside Pattern时,一定要合理地设置过期策略。如果过期时间太短,可能导致大量请求涌入数据库。相反,如果过期时间太长,有可能导致缓存中数据的大量失效。使用缓存的一个原则,就是尽量缓存那些相对静态的、频繁被读取的数据。

推荐使用Cache Aside Pattern;

但需根据自身业务场景合理变通。

通过给缓存设置合理过期时间,是保证最终一致性的解决方案。

思考:若删除缓存失败导致数据不一致:

保障的重试机制:消息队列

参考:redis缓存数据与数据库如何保持一致性_君莫笑_0808的博客-CSDN博客_如何保持redis和数据库一致

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐