1. 课程导入与问题定义

在几乎所有中大型互联网系统中,Redis 都扮演着“挡在数据库前面的高速缓冲层”这一角色。它把热点数据放在内存里,让读请求在毫秒级返回,从而把 MySQL、PostgreSQL 这类磁盘数据库从高并发读压力中解放出来。但正是这种“同一份数据存在两个地方”的架构,天然埋下了一个问题:当数据发生变更时,缓存和数据库谁先更新、谁后更新、更新失败怎么办?这就是缓存一致性问题。

要理解这个问题,先要理解它的来源。缓存一致性问题并不是 Redis 的缺陷,而是“多副本数据”的必然结果。数据库是数据的权威来源(Source of Truth),Redis 只是它的一个副本。当一次写操作发生时,数据库中的值变了,但 Redis 中的旧值不会自动消失。如果此时有读请求命中 Redis,就会读到过期数据。更麻烦的是,缓存和数据库的更新是两个独立的操作,它们之间没有分布式事务保证,任何一步失败、延迟或并发交错,都会让两者出现偏差。

缓存一致性问题的本质:数据被写入了两个存储介质,而这两个写入操作无法原子完成,于是产生了“时间窗口”和“失败窗口”。

我们可以用一个具体的场景来感受这个时间窗口。假设商品价格从 100 元调整为 80 元。如果采用“先更新数据库,再删除缓存”的策略:数据库更新成功,但在删除缓存之前,一个读请求进来,发现缓存里还有旧值 100 元,于是直接返回了 100 元。用户看到的价格就是错的。这个窗口可能只有几毫秒,但在高并发下,几毫秒足以让成百上千个请求读到脏数据。

缓存不一致带来的业务影响,远不止“显示一个错误数字”这么简单。在电商场景中,价格不一致可能导致用户下单金额错误,引发客诉和资损;在库存场景中,缓存中的库存比数据库多,会导致超卖;在账户余额场景中,缓存中的余额比实际多,可能被恶意利用;在配置中心场景中,缓存中的旧配置会让服务行为异常。更隐蔽的是,这类问题往往不是必现的,而是偶发、难以复现、难以定位的,排查成本极高。

因此,本课程的目标不是教你“背下几种更新策略”,而是建立一套完整的工程视角:从问题来源出发,理解不同策略的适用边界,掌握异常场景下的兜底手段,并能够根据业务的一致性要求做出合理取舍。一致性不是非黑即白的,它是一条从“强一致”到“最终一致”的光谱。工程上真正要回答的是:这个业务能容忍多长时间的脏数据?能容忍多大范围的不一致?为了把不一致窗口压到可接受范围,愿意付出多少复杂度和性能代价?

下面这张图从整体上展示了缓存一致性问题的产生链路,以及工程上需要关注的几个关键环节。它把“写请求—数据库—缓存—读请求”四者之间的时序关系和风险点放在同一张图中,帮助你在后续章节中建立全局坐标。

缓存一致性问题产生链路与工程关注点 写请求 更新价格/库存/余额 数据库(权威源) 新值 80 元已落盘 Redis 缓存 旧值 100 元仍存在 读请求 命中旧值 ① 写库 ② 删缓存(可能失败/延迟) ③ 读 风险窗口:数据库已更新,缓存尚未失效 此期间读请求会拿到旧值 → 脏读 工程上必须回答的四个问题 更新顺序 先库后缓存? 先缓存后库? 操作方式 删除缓存还是更新缓存? 延迟双删? 失败兜底 删除失败如何重试? 消息队列补偿? 一致性级别 强一致还是最终一致? 容忍窗口多大? 核心结论:一致性不是“有或无”,而是“窗口大小”与“代价取舍” 后续章节将围绕更新策略、延迟双删、消息补偿、读写分离一致性等逐一展开

从图中可以看到,问题的核心并不在于“Redis 会不会出错”,而在于数据库更新与缓存失效之间存在一个无法消除的时间差。工程上所有策略,本质上都是在做三件事:缩小这个时间差、在时间差内避免读到脏数据、以及在缓存失效失败时提供补偿机制。

在进入具体策略之前,还需要建立一个重要的认知:缓存一致性问题的严重程度,取决于业务对“脏数据”的容忍度。对于商品详情页的点赞数,短暂不一致几乎无影响;对于库存扣减,短暂不一致可能导致超卖;对于支付金额,任何不一致都是不可接受的。因此,本课程不会给出“唯一正确”的方案,而是提供一套判断框架:先明确业务的一致性要求,再选择匹配的策略组合。

学习建议:在后续每一章中,都带着三个问题去阅读——这个策略把不一致窗口缩小到了什么程度?它在什么异常场景下会失效?它的性能代价和实现复杂度是否匹配我的业务?

本课程的整体结构将沿着“问题定义 → 更新策略 → 异常处理 → 高并发场景 → 工程落地”这条主线展开。第1章建立全局视角后,第2章会深入分析“先更新数据库再删除缓存”与“先删除缓存再更新数据库”两种基础策略的差异与适用场景;随后会逐步引入延迟双删、消息队列补偿、binlog 订阅、读写分离下的主从延迟一致性等进阶话题。每一章都会给出可运行的示例参数、判断依据和异常处理方式,而不是停留在概念层面。

最后需要强调:缓存一致性没有银弹。任何声称“彻底解决”的方案,要么牺牲了性能,要么把复杂度转移到了别处。工程上的正确做法是:承认不一致窗口的存在,量化它,监控它,并为它设计兜底路径。当你能够清晰回答“我的系统在什么情况下会不一致、持续多久、影响什么业务、如何发现和恢复”时,你就真正掌握了缓存一致性的工程方法。