Redis的旁路缓存策略和先删除缓存后更新数据库,先更新数据库后删除缓存,这三种策略之间有什么关系??

文章目录

      • [1. 旁路缓存策略 (Cache Aside Pattern) ------ 总体架构](#1. 旁路缓存策略 (Cache Aside Pattern) —— 总体架构)
      • [2. 三者的逻辑演进与竞争态分析](#2. 三者的逻辑演进与竞争态分析)
        • [A. 先删除缓存,后更新数据库](#A. 先删除缓存,后更新数据库)
        • [B. 先更新数据库,后删除缓存(Cache Aside 标准做法)](#B. 先更新数据库,后删除缓存(Cache Aside 标准做法))
      • [3. 三种策略的关系总结表](#3. 三种策略的关系总结表)
      • [💡 深度思考:为什么是"删除"而不是"更新"缓存?](#💡 深度思考:为什么是“删除”而不是“更新”缓存?)

这是一个非常经典且高频的后端面试/实战问题。简单来说,它们之间的关系是: "旁路缓存(Cache Aside)"是一个宏观的架构模式,而另外两者是实现该模式中"更新操作"的具体时序方案。

作为后端开发者,你可以把它们看作是"抽象接口"与"具体实现"的关系。


1. 旁路缓存策略 (Cache Aside Pattern) ------ 总体架构

这是目前互联网最通用的缓存模式。它的核心逻辑分为两部分:

  • 读请求: 先读缓存,缓存命中则返回;缓存失效则读数据库,然后将数据写回缓存。
  • 写请求(关键点): 先更新数据库,然后让缓存失效(删除缓存)。

它们的联系就在这里: 当我们要执行"写请求"时,究竟是"先删缓存后更新数据库"还是"先更新数据库后删除缓存",这就是你提到的另外两种具体策略。


2. 三者的逻辑演进与竞争态分析

为了保证数据库(Source of Truth)和缓存的一致性,我们需要分析在并发环境下,这两种时序会发生什么。

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

这种方案在并发环境下非常脆弱,容易产生永久性脏数据

  1. 线程 A 执行写操作,先删除了缓存
  2. 此时线程 B 执行读操作,发现缓存缺失,去读数据库(旧值)
  3. 线程 B 将旧值写入缓存
  4. 线程 A 更新数据库(新值)
  • 结果: 缓存里永远是旧值,数据库里是新值。除非缓存过期,否则不一致会一直持续。
  • 修复方案: 采用"延时双删"策略(在更新完 DB 后,sleep 一段时间再删一次缓存)。
B. 先更新数据库,后删除缓存(Cache Aside 标准做法)

这是业界最推荐的方案,虽然理论上仍有极其微小的概率出现不一致,但概率极低。

  1. 线程 A 执行读操作,缓存刚好失效,读数据库(旧值)
  2. 线程 B 执行写操作,更新数据库(新值) ,然后删除缓存
  3. 线程 A 将此前读到的旧值写入缓存
  • 结果: 产生脏数据。
  • 为什么概率低? 因为步骤 3(写缓存)的速度远快于步骤 2(更新 DB),通常读线程会在写线程删除缓存前就完成写入。
  • 修复方案: 配合消息队列(MQ)进行重试删除,确保缓存最终一定被删掉。

3. 三种策略的关系总结表

维度 旁路缓存 (Cache Aside) 先删缓存,后更库 先更库,后删缓存
层级关系 架构模式(顶层设计) 写操作的具体实现方案 A 写操作的具体实现方案 B
核心目的 保证 DB 与 Cache 最终一致 试图通过先清理缓存来强制触发加载 默认方案,降低并发冲突概率
并发风险 取决于写操作的时序 极高(容易产生永久脏数据) 极低(仅在读快于写时发生)
典型补救 无(需结合具体方案) 延时双删 MQ 异步重试删除

💡 深度思考:为什么是"删除"而不是"更新"缓存?

在 Cache Aside 模式中,无论是 A 还是 B 策略,大家通常都选择删除缓存 (Delete),而不是更新缓存(Update)。原因有二:

  1. 性能开销: 如果缓存的数据是经过复杂计算得到的(比如多次 Join),每更一次库就更新一次缓存,代价太大。采用"懒加载"更合适。
  2. 并发安全: 如果两个写线程并发更新缓存,可能出现 DB 是新值,但缓存被旧的写请求覆盖的情况(类似丢失更新)。

总结建议:

在你的 Java 后端开发实践中(比如你之前提到的《小哈书》微服务项目),直接采用 "先更新数据库,后删除缓存" 即可。如果对一致性要求极高,可以引入 Canal 监听 MySQL binlog 来异步删除 Redis 缓存,这样可以解耦业务代码并解决删除失败的问题。

你目前的项目里,是否有遇到因为高并发导致的缓存不一致现象?如果有,我们可以针对具体的业务场景(比如点赞数、评论列表)聊聊更细化的处理手段。

相关推荐
ictI CABL2 小时前
redis连接服务
数据库·redis·bootstrap
苍煜2 小时前
SpringBoot单体应用到分布式下的数据库锁、事务、Redis事务、分布式锁、分布式事务协调
数据库·spring boot·分布式
风筝在晴天搁浅2 小时前
设置一个带超时时间的LRU缓存
缓存
AI进化营-智能译站2 小时前
ROS2 C++开发系列18-STL容器实战:deque缓存激光雷达数据|priority_queue调度任务
开发语言·c++·缓存·ai
xmjd msup2 小时前
mysql的分区表
数据库·mysql
Lyyaoo.2 小时前
【JAVA Spring面经】Spring 事务失效情况
java·数据库·spring
MeAT ITEM2 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
dovens3 小时前
PostgreSQL 中进行数据导入和导出
大数据·数据库·postgresql
IOT.FIVE.NO.13 小时前
claude code desktop cowork报错解决和记录Workspace..The isolated Linux environment ...
linux·服务器·数据库