【Redis】缓存与数据库一致性问题

67 阅读2分钟

数据库与缓存的一致性

在更新数据库后,希望缓存也能读到正确的数据

Why?

常见的错误:

  • 并发更新导致数据库与缓存不一致,两个并发写数据库:

    • 先更新缓存再更新数据库、先更新数据库再更新缓存都会有并发问题,导致不一致
  • 更新数据库后更新缓存失败

    • 旧数据一直霸榜,过期时间兜底

延迟双删

  • 读策略:发现缓存中没数据再从数据库中读取数据,更新到缓存中。

  • 写策略:更新数据库中的数据;删除缓存中的数据。

    • 先删后写:读写并发数据不一致

      • 解决办法:延迟双删:删除缓存,更新数据库,过一会再删除一遍缓存
    • 先写后删:缓存的写入通常要远远快于数据库的写入,不一致概率低

      • 后删失败,数据不一致,过期时间兜底
      • 分布式锁避免并发问题,性能--

如何保证先写后删两个操作都成功?

  • 重试机制

    • 第一次删除失败,将key加入消息队列,消费者复制再次删除
  • 订阅 MySQL binlog,再操作缓存。

    • Canal:模拟 MySQL 主从复制的交互协议,把自己伪装成一个 MySQL 的从节点,向 MySQL 主节点发送 dump 请求,MySQL 收到请求后,就会开始推送 Binlog 给 Canal,Canal 解析 Binlog 字节流之后,转换为便于读取的结构化数据,供下游程序订阅使用。

Read/Write Through(读穿 / 写穿)策略

应用程序只和缓存交互,不再和数据库交互,缓存和数据库交互,更新数据库的操作由缓存代理。

  • Read Through 策略

    • 先查询缓存中数据是否存在,如果存在则直接返回,如果不存在,则由缓存组件负责从数据库查询数据,并将结果写入到缓存组件,最后缓存组件将数据返回给应用。
  • Write Through 策略

    • 当有数据更新的时候,先查询要写入的数据在缓存中是否已经存在:

      • 已经存在:更新缓存中的数据,同步更新到数据库中,告知应用程序更新完成。
      • 不存在:直接更新数据库,然后返回;

Memcached、Redis 都支持。在使用本地缓存的时候可以考虑使用这种策略。

分布式锁

  • 读:发现缓存不存在,读数据库前加分布式锁
  • 写:加分布式锁再写数据库,写完释放锁+删缓存

分布式锁的实现:😡😡😡

Redis nx + double check