zoukankan      html  css  js  c++  java
  • redis缓存与数据库一致性

    Cache Aside Pattern

    (1)读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,同时返回响应

    (2)更新的时候,先删除缓存,然后再更新数据库

    先删除后更新

    避免更新过程中新来的读请求读到旧缓存数据。或者修改了数据库后删除缓存操作失败了,就会导致redis与数据库不一致的问题。

    为什么不是更新而是删除?

    • 避免不必要的计算
    • lazy懒加载思想,很多资源查询率并没有那么高,等到用时再去查就可以。

    超高并发场景

    如果亿级流量超高并发访问,cache aside pattern会出现删除缓存成功,但是更新数据库还没完成时新的读请求就来了,此时读库拿到应该要更新的旧数据又缓存起来,造成数据不一致的问题。

    可以设计一个队列让读写操作串行。

    1. 更新操作先删除缓存,然后放入队列等执行成功后出队
    2. 访问请求来到时发现缓存为空并且队尾有排队的更新操作,那么他就需要排队,等更新操作完成后再访问,完成后出队
    3. 访问请求来到时发现缓存为空并且队尾有排队的访问请求,不排队但是需要等待队列为空后再访问缓存

    该解决方案要注意读请求长时阻塞

    由于读请求进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求必须在超时时间范围内返回

    该解决方案,最大的风险点在于说,可能数据更新很频繁,导致队列中积压了大量更新操作在里面,然后读请求会发生大量的超时

    务必通过一些模拟真实的测试,看看更新数据的频繁是怎样的

    另外一点,因为一个队列中,可能会积压针对多个数据项的更新操作,因此需要根据自己的业务情况进行测试,可能需要部署多个服务,每个服务分摊一些数据的更新操作

    如果一个内存队列里居然会挤压100个商品的库存修改操作,每隔库存修改操作要耗费10ms区完成,那么最后一个商品的读请求,可能等待10 * 100 = 1000ms = 1s后,才能得到数据

    这个时候就导致读请求的长时阻塞

    一定要做根据实际业务系统的运行情况,去进行一些压力测试,和模拟线上环境,去看看最繁忙的时候,内存队列可能会挤压多少更新操作,可能会导致最后一个更新操作对应的读请求,会hang多少时间,如果读请求在200ms返回,如果你计算过后,哪怕是最繁忙的时候,积压10个更新操作,最多等待200ms,那还可以的

    如果一个内存队列可能积压的更新操作特别多,那么你就要加机器,让每个机器上部署的服务实例处理更少的数据,那么每个内存队列中积压的更新操作就会越少

  • 相关阅读:
    mysq 日期相减
    说说时间观与时间管理——北漂18年(71)
    ionic之切换开关
    ionic之单选框
    SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE locks在RR模式下可以看到最新的记录
    14.5.2.3 Consistent Nonlocking Reads 一致性非锁定读
    14.5.2.2 autocommit, Commit, and Rollback
    14.5.2 事务隔离级别
    对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间
    mysql explain 解释
  • 原文地址:https://www.cnblogs.com/ren-kai/p/12811622.html
Copyright © 2011-2022 走看看