缓存数据库双写不一致

发布时间 2024-01-10 09:59:41作者: 长城VIP

缓存数据库双写不一致

Redis 缓存与数据库 Mysql 双写不一致如何解决?方案2应该是最好的,也是最复杂的。其他都有很明显的问题。

  1. 对于频繁更新的数据不建议加缓存

  2. 异步更新缓存(基于订阅 binlog 的同步机制):binlog 增量订阅消费 + 消息队列 + 增量数据更新到 redis

    1. 读 Redis:热数据基本都在 Redis
    2. 写 Mysql:增删改都在数据库;
    3. 更新 redis 数据:数据库的操作是 binlog,来更新到 Reids(全量(全部写入 Redis),增量(实时更新))
    4. 读取 binlog 后,利用 MQ 推送更新各台的 redis 缓存数据;

    通过 Canal 组件监控 Mysql 中 binLog 日志的变化,把更新后的数据同步到 Redis 中。

    1. Canal 模拟 Mysql Slave 的交互协议,伪装自己为 Mysql Slave,向 Mysql Master 发送 dump 协议。
    2. Mysql Master 收到 dump 请求,开始推送 Binary log 给 slave(即 Canal)。
    3. Canal 解析 birary log 对象(原始为 Byte 流)。
  3. 面向缓存,所有读、写请求都在 Redis 中进行,发生写事件时由消息队列异步更新数据库。

    1. 漏洞:如果redis崩了,或者消息队列崩了,就有可能丢失数据,产生不一致。
    2. Redist作为数据库,并不能完全替代关系性数据库,很多还是要直接查询数据库。
  4. 如果是mybatis,可以重写mybatis的二级缓存。当执行更新操作时,异步清理掉对应mapper上的缓存。

    1. 局限性:仅限mapper层上的缓存,service缓存解决不了。
    2. 漏洞:如果另一个Java web 服务也在操作同一张表,但却没有缓存同步,就无解了
  5. 采用延时双删策略(双淘汰策略):在写入库前后都进行 redis.del(key)操作,设置合理超时时间(先删除缓存》写数据库》休眠毫秒==》再次删除缓存)

    1. 方案有以下几种:

      1. 先更新数据库,再删除缓存
      2. 先更新数据库,再更新缓存
      3. 先删除缓存,再更新数据库
      4. 先更新缓存,再更新数据库
    2. 漏洞:如果另一个Java web 服务也在操作同一张表,但却没有缓存同步,就无解了

    3. 漏洞:如果另一个Java web 服务也在操作同一张表,但却没有缓存同步,就无解了

  6. 设置缓存过期时间:给缓存设置过期时间短一些,所有写操作以数据库为准,只要达到缓存过期时间,则后面的读请求会从数据库读取新值然后回填缓存;

    1. 彻底佛系了。如果请求本就少,但是单个请求响应时间就很长。这个缓存加了和没加一样,没啥用。
  7. 如果不一致的数据是业务操作引起的,可以在业务操作时,对相应的缓存进行失效操作。

    1. 问题:一个业务操作会影响多少个缓存,如果漏掉问题就尴尬了。会造成线上bug
    2. 漏洞:如果另一个Java web 服务也在操作同一张表,但却没有缓存同步,就无解了