zoukankan      html  css  js  c++  java
  • 为什么说延时双删很扯淡

    redis和mysql数据一致性的问题

    在这里,我们讨论三种更新策略:

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

    第一种,先更新缓存,再更新数据库

    问题:更新缓存成功,更新数据库失败,导致数据不一致。

    第二种,先更新数据库,再更新缓存

    问题:

    1、A更新数据库

    2、B更新数据库

    3、B写入缓存

    4、A写入缓存

    出现数据不一致。

    考虑另一种情况, 有如下两点:
    (1)如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
    (2)如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。

    第三种,先删除缓存,再更新数据库。

    问题:

    1、A删除缓存

    2、B查询数据库获取旧值

    3、B更新了缓存

    4、A更新数据库

    出现数据不一致的问题

    延时双删

    public void write(String key,Object data){
    	redis.delKey(key);
    	db.updateData(data);
    	Thread.sleep(1000);
    	redis.delKey(key);
    }
    

    问题一:延时双删,演变成了:先更新数据库,再删除缓存。。。。

    比如:

    1、A删除缓存

    2、B查询数据库获取旧值

    3、B更新了缓存

    4、A更新数据库

    5、A延时删缓存

    1~3步执行后,数据库和缓存是一致的,相当于没删除。

    4~5步:先更新数据库,再删缓存。

    所以延时双删演变成了:先更新数据库,再删除缓存。问题还是没解决。。。

    为什么?假设,此时,在第4步执行之前,又来了个查询C,C查询到旧值。第6步:C将旧值插入缓存。此时出现缓存和数据库不一致。

    延时并不能解决:C插入缓存的操作在第5步后面执行,比如C遇到网络问题、GC问题等。当然这是小概率,但并不代表不存在。

    当然,延时越长,这个问题越能规避。如果业务需求不是非常严格,是可以忽略的。

    问题二:吞吐量

    问题三:数据库更新后,无法保证下一次查询,从缓存获取的值和数据库是一致的。

    第四种,先更新数据库,再删除缓存

    问题:上面C的查询,已经说明问题了。

    出现数据不一致的概率,比较小。采取这个方案,取决于业务需求。

    终极方案

    请求串行化

    真正靠谱的方案:将访问操作串行化

    1. 先删缓存,将更新数据库的操作放进有序队列中
    2. 从缓存查不到的查询操作,都进入有序队列

    需要解决的问题:

    1. 读请求积压,大量超时,导致数据库的压力:限流、熔断
    2. 如何避免大量请求积压:将队列水平拆分,提高并行度。
    3. 保证相同请求路由正确。
  • 相关阅读:
    (IDEA) VCS-->Import Into Version Control没有Share Project(Subversion)这个选项。
    Maven学习笔记(二)—— 整合SSH框架
    Maven学习笔记(一)—— Maven基础
    使用IDEA完成maven整合SSH框架时抛出Hibernate : Mapping (RESOURCE) not found
    mysql性能的检查和优化方法
    每个php程序员都应该知道的15个最佳PHP库
    linux oracle 11g 漏洞补丁升级
    linux 启动MongoDB
    linux 7 查看oracle 11g版本号
    linux 清除缓存命令
  • 原文地址:https://www.cnblogs.com/zhouj-happy/p/12616906.html
Copyright © 2011-2022 走看看