数据库和 Redis 之间没有天然原子事务。多数读多写少系统以“先提交数据库,再删除缓存”为起点,接受短暂最终一致,并用重试、版本和观测缩小异常窗口。
Table of contents
Open Table of contents
为什么通常更新后删除
直接更新缓存需要复制数据库的写规则,还可能按错误顺序覆盖新值。删除让下次读取从权威数据源重建。实验中的更新流程是:
repository.updateProduct(id, value);
cache.delete("product:" + id);
mvn -Dtest=CacheEngineeringTest#updateDatabaseBeforeDeletingCache test
数据库提交成功而删除失败时,旧缓存会保留到 TTL。应用应记录失效事件并重试,缓存仍要有上限 TTL。
一个并发旧值窗口
读请求 R 未命中后开始查数据库;写请求 W 更新数据库并删除缓存;R 随后把先前读到的旧值写回缓存。结果是旧值继续存在到过期。这个窗口较窄,但在慢查询和热点下会出现。
可选治理包括延迟后再次删除、回填时携带数据版本并拒绝旧版本、缩短 TTL,或让单个 Key 的加载与更新串行化。延迟双删依赖延迟估计,不是严格一致证明。
CDC 和事件驱动解决什么
CDC 是 Change Data Capture,变更数据捕获。Canal 等工具订阅 MySQL Binlog,把已提交变更转换为缓存失效事件。另一种方式是业务事务写 Outbox 表,由可靠发布器发送事件。
事件可能重复、延迟和乱序。消费者要幂等,事件要带主键、操作类型、提交位置或版本,并有积压监控与死信处理。CDC 链路故障时,TTL 是最终兜底,不应设置为永久缓存。
先定义一致性等级
商品描述允许旧 30 秒,支付状态可能要求写后读主库,权限撤销要求更短窗口并主动推送。逐接口记录最大陈旧时间、回源策略和失败行为,比笼统要求“强一致缓存”更可执行。
下一步
继续阅读07-09 热点 Key 探测、隔离与本地缓存,把高频访问从事后告警变成实时治理信号。