• Redis 先写数据库及先写缓存一致性问题


    在这里插入图片描述
    从图中可以看到,Tomcat 上运行的应用,无论是新增(Insert 操作)、修改(Update 操作)、还是删除(Delete 操作)数据 X,都会直接在数据库中增改删。当然,如果应用执行的是修改或删除操作,还会删除缓存的数据 X。

    1、新增数据

    如果是新增数据,数据会直接写到数据库中,不用对缓存做任何操作,此时,缓存中本身就没有新增据,而数据库中是最新值,此时,缓存和数据库的数据是一致的。

    2、删改数据

    如果发生删改操作,应用既要更新数据库,也要在缓存中删除数据。这两个操作如果无法保证原子性

    2.1、不考虑并发性

    1. 先删除缓存值后更新数据库值:数据库更新失败,导致请求再次访问缓存时,发现缓存缺失,在读数据库时,从数据库中读到的是旧值
      在这里插入图片描述
    2. 先更新数据库,后删除缓存值:缓存删除失败,导致请求再次访问缓存时,发现缓存命中,并从缓存中读到旧值。
      在这里插入图片描述

    2.1.1、如何解决缓存数据不一致

    1. 重试机制:借助消息队列,可以把要删除的缓存值或者是要更新的数据库值暂存到消息队列中(例如使用Kafka 消息队列)。当应用没有能够成功地删除缓存值或者是更新数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或更新。缓存操作成功后,删除消息队列,防止重复消费导致一致性问题
      在这里插入图片描述

    2.2、高并发场景都成功

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

    假设线程 A 删除缓存值后,还没有来得及更新数据库(比如说有网络迟),线程 B 就开始读取数据了,那么这个时候,线程 B 会发现缓存缺失,就只能去数据库读取。这会带来两个问题:

    • 线程 B 读取到了旧值;
    • 线程 B 是在缓存缺失的情况下读取的数据库,所以,它还会把旧值写入缓存,这可能会导致其他线程从缓存中读到旧值。

    等到线程 B 从数据库读取完数据、更新了缓存后,线程 A 才开始更新数据库,此时,缓存中的数据是旧值,而数据库中的是最新值,两者就不一致了。
    在这里插入图片描述

    2.2.2、如何解决缓存数据不一致:延迟双删

    延迟双删在线程 A 更新完数据库值以后,我们可以让它先 sleep 一小段时间,再进行一次缓存删除操作。

    要加上 sleep 的这段时间,就是为了让线程 B 能够先从数据库读取数据,再把缺失的数据写入缓存,然后,线程 A 再进行删除。所以,线程 A sleep 的时间,就需要大于线程 B 读取数据再写入缓存的时间。

    伪代码

    redis.delKey(X)
    db.update(X)
    Thread.sleep(N)
    redis.delKey(X)
    
    • 1
    • 2
    • 3
    • 4

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

    如果线程 A 删除了数据库中的值,但还没来得及删除缓存值,线程 B 就开始读取数据了,那么此时,线程 B 查询缓存时,发现缓存命中,就会直接从缓存中读取旧值。不过,在这种情况下,如果其他线程并发读缓存的请求不多,那么,就不会有很多请求读取到旧值。而且,线程 A 一般也会很快删除缓存值,这样一来,其他线程再次读取时,就会发生缓存缺失,进而从数据库中读取最新值。所以,这种情况对业务的影响较小。
    在这里插入图片描述

    3、总结

    在这里插入图片描述

  • 相关阅读:
    深度学习应用篇-计算机视觉-图像分类[3]:ResNeXt、Res2Net、Swin Transformer、Vision Transformer等模型结构、实现、模型特点详细介绍
    python经典百题之判断回文数
    数据存储技术的相关概念
    MotionLayout的使用
    SpringCloud 网关 Gateway
    Redis 集群
    3.30 OrCAD中原理图文件怎么进行DRC检测?
    【Linux C】Linux如何执行一个程序(程序存储空间、系统调用、内核调用)
    人工智能在制造业的工程化应用实践----工业软件讲坛第九次讲座
    RF allure-windows 报告生成
  • 原文地址:https://blog.csdn.net/Extraordinarylife/article/details/127345801