25 | 缓存异常(上):如何解决缓存和数据库的数据不一致问题?

229 阅读2分钟

基本概念

  • 缓存导致的异常问题

    • 缓存中数据不一致
    • 缓存雪崩
    • 缓存击穿
    • 缓存穿透

为什么缓存与数据库不一致

  • 一致性

    • 缓存中有数据,且缓存数据和数据库数据相同
    • 缓存中没有数据,数据库必须为最新值
  • 根据是否接受写请求缓存分类

    • 读写缓存 
    • 只读缓存
  • 针对读写缓存 保证数据一致性需要将数据写回数据库

    • 同步直写策略:写缓存时同步到数据库,保证数据一致

      • 但是需要用事务保证两边都更新成功,或者两边都更新失败,否则数据还是不一致的
    • 异步写回策略:等数据淘汰写回数据库

  • 针对只读数据

    • 基本概念:数据更新时,将缓存删除即可,下次读数据回写到缓存中

    • 场景

      • 新增数据:缓存中没有数据,数据是一致的

      • 删改数据:需要保证缓存的删除和数据库的更新操作是原子的,否则会导致数据不一致\

        • 删除缓存,更新数据库:缓存删除成功,数据库更新失败  返回的仍然是旧值
        • 先更新数据,后更新缓存:缓存未删除掉,读到仍然是旧数据

针对只读缓存的情况

如何解决不一致

  • 重试机制

    • 删除的缓存或者更新的数据库只缓存到消息队列中,例如kafka,删除失败时再次重新删除
    • 如果删除成功则从消息队列中去除,避免重复操作
    • 失败则重试,超出重试次数后发出警报
  • 先删除缓存再更新数据库

    • 问题:如果更新操作未结束,会导致将旧数据读会缓存中
    • 解决办法:更新操作结束后,sleep一下删除缓存,保证b线程的数据写入缓存后再删除掉 (数据双删
  • 先更新数据库,再删除缓存

    • 可能会读取到旧值,删除操作很快,不会影响

总结

  • 解决方案

    • 删除和更新失败可以使用消息队列进行重试
    • 对于删除过程中的读操作读取旧值,可以采取延时双删
  • 大部分场景下都是只读缓存,不涉及更新数据操作(尽量使用更新数据库后删除缓存

    • 先删除缓存值再更新数据库,有可能导致请求因缓存缺失而访问数据库,给数据库带来压力(即使脏数据,也读缓存)
    • 双删的延迟时间不好估算

\