zoukankan      html  css  js  c++  java
  • 双写一致性的讨论

    简介

    双写一致性的目的:我们要达到最终一致性!

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

    我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存,达到一致性,切记以mysql的数据库写入库为准

    下面讨论三种更新策略:

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

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

    异常问题:

    1.先更新mysql的某商品库存,当前库存是100,更新到99

    2.更新mysql成功,然后更新reids

    3.此时假设异常出现,更新redis失败,这会导致mysql里面库存是99,redis里面还是100

    4.上述发生,会让数据库里面和缓存redis里面数据不一致,读到脏数据。

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

    异常问题:

    • 先删除redis里面的数据,然后正在更新mysql时,但是还没有更新结束,另一个线程突然出现要来读取缓存数据,此时redis里面数据是空的,从mysql获得了旧值,并把旧值写回redis(刚被删除的数据有可能被写回到redis
    • 高并发情况下,可能造成缓存击穿或缓存穿透

    延时双删方案

    在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。具体步骤是:

    1)先删除缓存

    2)再写数据库

    3)休眠500毫秒(根据具体的业务时间来定)

    4)再次删除缓存。

    那么,这个500毫秒怎么确定的,具体该休眠多久呢?

    需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

    当然,这种策略还要考虑 redis 和数据库主从同步的耗时。最后的写数据的休眠时间:则在读数据业务逻辑的耗时的基础上,加上几百ms即可。比如:休眠1秒。

    当然第二次删除可以采用异步删除。

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

    出现问题如下:

    1.线程A先修改数据库中的值,还没有来得及删除缓存,然后线程B读取到缓存的旧数据,最后线程A更新缓存的数据。

    canal解决方案:

    image-20211122104027581

    总结

    image-20211124102214342

  • 相关阅读:
    Python queue 模块详解
    贪婪算法的解题思路
    python中os.path.abspath和os.path.realpath区别
    python报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 4: ordinal not in range
    Python Socket Error: Address already in use的解决办法
    Python里的string 和 unicode 区别讲得很明白的文章
    linux环境,crontab报错Authentication token is no longer valid; new one required You (aimonitor) are not allowed to access to (crontab) because of pam configuration.
    Mac系统使用Parallels Desktop安装Win10
    windows update国内服务器
    黄海机器的向日葵远程帐号
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/15596968.html
Copyright © 2011-2022 走看看