Skip to main content

写DB再删除缓存,结果Redis宕机?

作者:程序员马丁

在线博客:https://open8gu.com

note

大话面试,技术同学面试必备的八股文小册,以精彩回答应对深度问题,助力你在面试中拿个offer。

回答话术

一般来说,为了避免因执行 Redis 操作而引起的性能问题对 MySQL 数据库造成事务长时间不提交等影响,我们会将 Redis 的执行操作置于数据库事务之外。

我猜测大部分同学在实际写代码中,可能会把缓存和数据库事务都放一起了,通常不建议这么做,具体原因看下文讲解。

image.png

因为数据库事务已经提交了,所以删除 Redis 缓存操作即使失败,也不能让接口操作返回失败。Redis 操作缓存失败有以下几种情况:

  • 客户端执行 Redis 操作超时,这个超时通常由客户端设置。导致超时的情况有很多种,比如 Redis 节点主线程执行某个流程阻塞,就有可能导致大量操作超时。
  • 获取不到 Redis 连接,因为单个 Redis 节点的连接有限,如果用完了则无法获取,进而报错。
  • 如果 Redis 服务器宕机或网络不可用,将导致无法执行任何 Redis 操作。
  • 由于网络故障或延迟,可能导致 Redis 操作失败。

以上几个,在面试中说出 1-2 个即可,说太多也没啥用,主要就是突出执行操作会失败。

我们可以通过以下几种解决方案完成缓存和数据库的最终一致性。

1. 设置缓存 Key 有效期

设置 Redis 中的 Key 较短的有效期,这个有效期不能太长,会直接影响到用户看到脏数据的时间。

image.png

这种解决方案是最简单的,不需要代码变更以及引入新的中间件技术等。不过也会带来一个问题,那就是 Redis 恢复了,但是不能马上解决数据问题,而是需要等过期时间。在这个期间,全靠数据库来做兜底。

除非 Redis 宕机又恢复后,有另一个相同操作变更了数据库,进而直接删除缓存。否则在这个期间缓存和数据库将无法保持一致。

2. 通过定时任务 + 数据库

定义数据库表 t_del_cache_event,其中有两个字段,需要删除的 Key 字段 del_cache_key,以及是否已执行字段 executed

当删除 Redis Key 报错时,在 catch 块中将该数据存入数据库,设置状态为未执行。然后项目中应该有个定时任务在执行扫描 t_del_cache_event 表,扫描的周期很有讲究,建议设置为预期让 Redis 服务恢复的时间。比如你觉得公司恢复 Redis 大概在 5 分钟,就可以设置为 5 分钟扫描一次。

image.png

执行删除缓存 Key 后,我们就可以设置是否执行字段 executed 为已执行,后续再定期删除。

该解决方案引入了定时任务和数据库,带来了一定的复杂性。不过相比上一个方案硬等 Key 自己过期,这个方案的能更及时的更新数据,保证数据的时效性。

3. 通过延时消息队列

解锁付费内容,👉 戳