• redis缓存与数据库一致性


    Cache Aside Pattern

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

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

    先删除后更新

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

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

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

    超高并发场景

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

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

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

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

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

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

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

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

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

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

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

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

  • 相关阅读:
    2018/12/06 L1-031 到底是不是太胖了 Java
    2018/12/06 L1-030 一帮一 Java
    2018/12/06 L1-029 是不是太胖了 Java
    .NET Framework 类库命名空间
    .NET获取根目录
    ddd领域驱动设计
    垃圾回收
    rest api
    数据库ACID
    事务隔离级别
  • 原文地址:https://www.cnblogs.com/ren-kai/p/12811622.html
Copyright © 2020-2023  润新知