浅谈Redis缓存和数据库一致性问题

最近面试季节,估计「如何保证缓存和数据库一致性」这个问题经常会被问到,这是一个老生常谈的话题了。

但很多人对这个问题,依旧有很多疑惑:

  • 到底是更新缓存还是删缓存?
  • 到底选择先更新数据库,再删除缓存,还是先删除缓存,再更新数据库?
  • 为什么要引入消息队列保证一致性?
  • 延迟双删会有什么问题?到底要不要用?
  • ...

这篇文章,我们就来把这些问题讲清楚。

这篇文章干货很多,希望你可以耐心读完。

浅谈Redis缓存和数据库一致性问题_第1张图片

引入缓存提高性能

我们从最简单的场景开始讲起。

如果你的业务处于起步阶段,流量非常小,那无论是读请求还是写请求,直接操作数据库即可,这时你的架构模型是这样的:

浅谈Redis缓存和数据库一致性问题_第2张图片

但随着业务量的增长,你的项目请求量越来越大,这时如果每次都从数据库中读数据,那肯定会有性能问题。

这个阶段通常的做法是,引入「缓存」来提高读性能,架构模型就变成了这样:

浅谈Redis缓存和数据库一致性问题_第3张图片

当下优秀的缓存中间件,当属 Redis 莫属,它不仅性能非常高,还提供了很多友好的数据类型,可以很好地满足我们的业务需求。

但引入缓存之后,你就会面临一个问题:之前数据只存在数据库中,现在要放到缓存中读取,具体要怎么存呢?

最简单直接的方案是「全量数据刷到缓存中」:

  • 数据库的数据,全量刷入缓存(不设置失效时间)
  • 写请求只更新数据库,不更新缓存
  • 启动一个定时任务,定时把数据库的数据,更新到缓存中

浅谈Redis缓存和数据库一致性问题_第4张图片

这个方案的优点是,所有读请求都可以直接「命中」缓存,不需要再查数据库,性能非常高。

但缺点也很明显,有 2 个问题:

  1. 缓存利用率低:不经常访问的数据,还一直留在缓存中
  2. 数据不一致:因为是「定时」刷新缓存,缓存和数据库存在不一致(取决于定时任务的执行频率)

所以,这种方案一般更适合业务「体量小」,且对数据一致性要求不高的业务场景。

那如果我们的业务体量很大,怎么解决这 2 个问题呢?

缓存利用率和一致性问题

先来看第一个问题,如何提高缓存利用率?

想要缓存利用率「最大化」,我们很容易想到的方案是,缓存中只保留最近访问的「热数据」。但具体要怎么做呢?

我们可以这样优化:

  • 写请求依旧只写数据库
  • 读请求先读缓存,如果缓存不存在,则从数据库读取,并重建缓存
  • 同时,写入缓存中的数据,都设置失效时间

浅谈Redis缓存和数据库一致性问题_第5张图片

这样一来,缓存中不经常访问的数据,随着时间的推移,都会逐渐「过期」淘汰掉,最终缓存中保留的,都是经常被访问的「热数据」,缓存利用率得以最大化。

再来看数据一致性问题。

要想保证缓存和数据库「实时」一致,那就不能再用定时任务刷新缓存了。

所以,当数据发生更新时,我们不仅要操作数据库,还要一并操作缓存。具体操作就是,修改一条数据时,不仅要更新数据库,也要连带缓存一起更新。

但数据库和缓存都更新,又存在先后问题

你可能感兴趣的:(架构,java,面试,缓存,数据库,redis,java,面试)