redis灵魂拷问系列之如何保证数据库和缓存双写一致性


redis灵魂拷问系列之如何保证数据库和缓存双写一致性

1.什么是数据库缓存双写一致性呢?

一般为了加快查询响应速度等,我们通过加缓存来提高接口的QPS,例如redis缓存、JVM缓存等。

数据是 缓存和数据库共享的。在 高并发场景下更新数据 时,因为数据库和缓存都要更新,就很可能会有数据一致性问题,其实也是分布式场景下数据一致性的问题

什么时候会发生数据库缓存双写不一致的情况呢?

例如:高并发场景下,先更新数据库,再删除缓存之后,另外一个线程把旧数据存入缓存

2.选择更新缓存还是删除缓存?

这里就需要提到Cache Aside Pattern,也是我们日常编码中一般会采取的策略

  1. 读取数据时,先读缓存,缓存不存在再读数据库,然后把结果存入缓存
  2. 更新数据时,先更新数据库,再删除缓存

为什么是删除缓存不是更新缓存呢?

假如为 更新缓存

  • 如果数据更新频繁,则每一次都需要更新缓存,如果加上还是联表查询,则更新缓存的代价就很大
  • 如果数据不会被频繁查询到(冷数据),这时候频繁更新缓存则是在浪费资源(例如数据A一分钟内被更新20次,但是只查询了一次)
  • 还可能存在更新缓存失败的情况

假如为 删除缓存

  • 数据在删除后,第一次被访问时,会从数据库读取(类似懒加载方式),保证了只有被用到才去操作,减少了资源浪费

所以当之无愧,选择 删除缓存

3.先更新数据库,还是先删除缓存?

  1. 先删除缓存,删除成功后去更新数据库。会出现问题:高并发场景下,删除成功后,可能另外一个请求查询后又把旧数据存入缓存中。这时候要么采用 延迟双删,也就是睡眠一定时间后再次删除一次,要么选择下一种做法
  2. 先更新数据库,再删除缓存。会出现问题:高并发下,在删除成功后,可能其他线程把旧数据再存入缓存中的问题。也会出现数据不一致的情况(影响相对较小所以可以接受)

4.具体落地的解决策略有哪些?

(1)延时双删策略

  • a. 删除缓存
  • b. 更新数据库
  • c. 睡眠一段时间,具体多长有业务决定(mysql读写分离的话还需要加上主从同步时间)
  • d. 再删除缓存(吞吐量降低的话使用 异步

(2)更新数据库、后删缓存

(3)串行化思维保证两者的最终一致性

利用binlog天然的顺序性用来做同步操作,顺序删除缓存,删除缓存失败则使用消息队列的同步性重试删除缓存

(4)强一致性

如果需要保证强一致性,那么是否还有添加缓存的必要(没有海量qps的情况下)?

可以参考这篇文章:缓存与数据库一致性系列-04 - Kido的博客 | Kido’s Blog

【参考链接】
1:Redis与Mysql双写一致性方案解析
2:缓存与数据库一致性系列-03
3:缓存与数据库一致性系列-04


评论
  目录