如何保证缓存一致性


1.如何保证缓存一致性?

使用缓存代表不需要强一致性,只需要最终一致性

1.1数据库和缓存数据强一致场景:

  • 同步双写:更新 DB 时同样更新 cache,保证在一个事务中,通过加锁来保证更新 cache 时不存在线程安全问题

  • 延迟双删:先淘汰缓存再写数据库,休眠 1 秒再次淘汰缓存,可以将 1 秒内造成的缓存脏数据再次删除

  • 异步通知:

    • 基于 MQ 的异步通知:对数据的修改后,代码需要发送一条消息到 MQ 中,缓存服务监听 MQ 消息
    • Canal 订阅 MySQL binlog 的变更上报给 Kafka,系统监听 Kafka 消息触发缓存失效,或者直接将变更发送到处理服务,没有任何代码侵入

    低耦合,可以同时通知多个缓存服务,但是时效性一般,可能存在中间不一致状态

1.2低一致性场景:

  • 更新 DB 的时候同样更新 cache,但是给缓存加一个比较短的过期时间,这样就可以保证即使数据不一致影响也比较小
  • 使用 Redis 自带的内存淘汰机制

2.先操作数据库还是先操作redis

在保证Redis缓存一致性时,优先选择先更新数据库再删除缓存(Cache-Aside Pattern),这是业界主流方案。

2.1为什么先更新数据库再删除缓存?

  • 逻辑合理性:数据库是数据的唯一权威来源,缓存应作为数据库的从属。先更新数据库可确保数据源头的正确性.
  • 并发安全:若先删除缓存再更新数据库,在并发场景下可能导致旧数据回填缓存,例如:请求A把缓存删了,还没来得及更新数据库,请求B读取了数据库旧值并写入缓存(这里可以想象缓存是永不过期的),而先更新数据库再删除缓存能降低此类风险。

3.延迟双删

public void write(String key, Object data) {
    redis.del(key);          // 第一次删除
    db.update(data);         // 更新数据库
    Thread.sleep(1000);      // 等待读请求完成
    redis.del(key);          // 第二次异步删除
}

文章作者: Fuchanglai
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Fuchanglai !
赏
  目录