这里写目录标题

  • 缓存一致性
  • 先更新数据库,后更新缓存
  • 先更新缓存,后更新数据库
  • 先删除缓存,后更新数据库
  • 先更新数据库,后删除缓存
  • 延时双删
  • 删除缓存失败怎么办
  • Redis在更新数据库的值时,为什么要删除缓存,而不是更新缓存


缓存一致性

保证缓存与数据库双写时数据一致性的所有策略有四种:(1)先更新数据库,后更新缓存;(2)先更新数据库,后删除缓存;(3)先更新缓存,后更新数据库;(4)先删除缓存,后更新数据库。

先更新数据库,后更新缓存

这种场景一般是没有人使用的,主要原因是在更新缓存那一步,为什么呢?因为有的业务需求缓存中存在的值并不是直接从数据库中查出来的,有的是需要经过一系列计算来的缓存值,那么这时候后你要更新缓存的话其实代价是很高的。如果此时有大量的对数据库进行写数据的请求,但是读请求并不多,那么此时如果每次写请求都更新一下缓存,那么性能损耗是非常大的。

先更新缓存,后更新数据库

这一种情况也不需要考虑,和第一种情况是一样的。

先删除缓存,后更新数据库

该方案也会出问题,具体出现的原因如下图:

MySQL 缓存 db一致性 数据库 缓存一致性_mysql

当请求 A执行清除缓存后,还未进行数据库更新,此时请求 B进行查询,查到了旧数据并写入了 Cache。

先更新数据库,后删除缓存

该方案也会出问题:当请求 A更新数据库之后,还未来得及进行缓存清除,此时请求 B查询到并使用了 Cache中的旧数据。

延时双删

延时双删策略的具体步骤是:

  1. 先删除缓存。
  2. 再写数据库。
  3. 休眠N秒。
  4. 再次删除缓存。

N是多大比较合适呢?一般来说,N要大于一次写操作的时间,如果延迟时间小于写入缓存的时间,会导致请求A已经延迟清除了缓存,但是此时请求B缓存还未写入,相当于做了无效的删除操作。

为什么要两次删除缓存?

  1. 只先删缓存的话,当我们在清除缓存和更新数据库间有事务查询缓存,此时没有缓存,数据库还没更新,所以缓存又更新为旧数据了。
  2. 只后删缓存的话,在删除缓存之前读到的数据都是旧数据。

删除缓存失败怎么办

更新数据库成功了,但是在删除缓存的阶段出错了没有删除成功,那么此时再读取缓存的时候每次都是错误的数据了,此时解决方案就是利用消息队列进行删除的补偿,如下图所示。具体的业务逻辑用语言描述如下:

  1. 请求 A 先对数据库进行更新操作。
  2. 在对 Redis 进行删除操作的时候发现报错,删除失败。
  3. 此时将Redis 的 key 作为消息体发送到消息队列中。
  4. 系统接收到消息队列发送的消息后再次对 Redis 进行删除操作。

MySQL 缓存 db一致性 数据库 缓存一致性_MySQL 缓存 db一致性_02

Redis在更新数据库的值时,为什么要删除缓存,而不是更新缓存

如果写数据库的值与更新缓存的值不一致,并且写入缓存中的数据需要经过几个表的关联计算后得到,那就没有必要马上更新缓存,只要删除缓存即可,等到查询的时候在去把计算后得到的结果插入到缓存中即可。其实删除缓存,而不是更新缓存,就是一个lazy计算的思想。