Redis 与数据库如何保持一致?先明确允许多旧的数据

无敌码农编辑部 · 发布于 2026-10-29

60 秒回答

常见的 Cache Aside 模式是读时查缓存,未命中再查数据库并回填;写时先更新数据库,再删除缓存。这个顺序便于实现,但不提供严格一致性。我会先明确业务允许的陈旧时间,再用过期时间、删除重试或变更事件缩小不一致窗口。账户余额等必须读取最新状态的场景,不能只依赖普通缓存。

为什么通常选择删除

更新缓存需要准确构造最新值,多个写请求还可能以相反顺序完成缓存更新。删除把重建工作交给后续读取,减少一份写逻辑。不过数据库提交与 Redis 删除属于两个独立操作,不能因为代码里挨着写就当成同一个事务。

先删除缓存再更新数据库也有窗口:其他请求可能在数据库尚未提交时读到旧值,并把它回填。先提交再删除通常更容易控制,但依然需要讨论并发和失败。

一个容易漏掉的并发过程

请求 A 缓存未命中,读取到数据库旧值;请求 B 更新数据库并删除缓存;随后 A 才把旧值写回缓存。删除成功了,缓存仍然可能陈旧。普通 Cache Aside 不能完全排除这个过程。

过期时间给陈旧值提供存活上限,但热点数据不断刷新、业务自己续期等行为会改变上限。对强实时字段,可以直接读主库、按版本校验,或者设计明确的并发控制;不要给所有字段套同样的方案。

删除失败怎样处理

数据库提交成功后,删除缓存可能因为网络失败而未完成。业务不能假装整个写入没有发生;应记录缓存失效失败,有限重试。需要可靠补偿时,可以在业务事务内写出站事件,再由消费者执行失效,并使消费可重复。

这会增加表、任务与排错成本,应由实际陈旧风险决定是否引入。延迟双删可以降低某些竞态概率,但延迟多久取决于请求耗时,无法作为严格一致性的证明。

如何验证而不是只背流程

在隔离环境控制读取和回填的先后顺序,复现旧值回填;再模拟 Redis 删除超时,观察数据库结果、缓存存活时间和补偿任务。验证指标是用户最多看到多久的旧值,以及失败能否被发现,不只是接口返回成功。

本文没有对具体系统进行压测。面试时可以按“业务容忍度、读写顺序、一个竞态、一个失败处理”组织回答,明确方案保证与边界。对价格、库存、余额等字段,还要分别讨论显示值与交易校验值,交易决策应使用权威数据。

参考资料

内容用于技术学习与求职准备,实际方案请结合版本和业务环境验证。如发现错误,欢迎通过关于页面反馈。

继续阅读