zoukankan      html  css  js  c++  java
  • 分布式系统之数据库和缓存双写一致性

    1. 缓存使用目的

    缓存由于其高并发和高性能的特性,已经在项目中被广泛使用(IO cost比数据库低了几个数量级,redis是从内存中读取数据, mysql是从磁盘读取数据)

    2. 读取数据

    流程无异议:

    1.   判断是否有缓存 
    2. 有,直接返回数据给调用端. 无,跳到3 
    3. 从数据库加载数据,有数据直接写入缓存,无数据则跳到4
    4. 若不写入缓存, 可能发生缓存穿透(缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。)。可以缓存空对象来解决缓存穿透问题。
    5. 返回空数据。

    3. 更新缓存

            3.1更新策略  

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

           3.2 策略分析

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

              技术角度分析: 多线程更新数据库和缓存时,并不能保证次序,比如A线程先发起,然后B线程后发起,但是B线程可能比A线程先更新缓存,这就导致了缓存最后的值是A线程的值导致数据库和缓存不一致

              业务角度分析:1. 加入业务是写多读少的场景,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。2. 加入写入缓存的值是要在数据库更新后,经过一系列计算再更新缓存的,采用此方案会造成性能浪费。

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

              比如一个写线程A, 一个读线程B,在A线程删除缓存后,B线程发现缓存不存在就去读取数据库旧值,然后更新缓存,然后A线程才更新数据库,如此也会造成数据库缓存不一致。

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

             这种方式同样有并发访问问题。同样2个线程,缓存失效,线程A探知缓存失效,查询数据库,取得旧值,线程B更新数据库并且删除缓存key,线程A将旧值写入缓存。

             但一般来说数据库IO远远慢比缓存IO,所以一般线程A写入缓存会发生在线程B删除缓存之前。

    另外还有一个问题就是删除缓存不成功,用重试机制保障删除操作,一个是用消息队列,另一个是订阅binlog日志来更新缓存(canal)。

  • 相关阅读:
    nuxt实践
    安卓H5软键盘遮挡输入框
    h5复制粘贴板,打开APP功能
    MVC3
    MVC3
    C#高编
    接口的显式实现(转)
    E-Retail 框架学习
    C#高编
    实现DIV居中布局三种途径(转)
  • 原文地址:https://www.cnblogs.com/frank2015/p/9678790.html
Copyright © 2011-2022 走看看