Redis缓存一致性(Cache Consistency)问题,如何避免脏数据(stale data)?(Cache Aside旁路缓存、过期时间TTL、订阅数据库变更Binlog、延迟双删)
文章目录一、问题本质缓存与数据库不一致二、常见解决方案重点1️⃣ Cache Aside旁路缓存 删除缓存最常用写操作流程关键为什么要“删缓存”而不是“更新缓存”正确时序很重要2️⃣ 延迟双删解决并发问题3️⃣ 设置过期时间TTL4️⃣ 主动更新缓存适用于强一致要求5️⃣ 使用消息队列保证一致性进阶6️⃣ 订阅数据库变更Binlog方案三、工程实践推荐方案结论✅ Cache Aside 删除缓存 TTL四、不同一致性要求的选择五、关键总结Redis 缓存设计里一个非常核心的问题缓存一致性Cache Consistency。在 “Cache Aside旁路缓存”模式下如果处理不当就会出现脏数据stale data。一、问题本质缓存与数据库不一致架构是客户端 - 应用 - Redis - 数据库问题发生在这个场景1. 查询Redis缓存了旧数据 2. 数据库被更新例如用户改了昵称 3. Redis 没更新 4. 再次查询命中 Redis → 返回旧数据 ❌这就是典型的缓存与数据库不一致问题二、常见解决方案重点在使用 Redis 时业界主要有几种成熟策略。1️⃣ Cache Aside旁路缓存 删除缓存最常用写操作流程关键1. 更新数据库 2. 删除缓存注意不是更新缓存而是删除缓存为什么要“删缓存”而不是“更新缓存”原因很现实缓存结构可能复杂更新成本高容易出现并发问题删除后下一次查询 → Redis miss → 查数据库 → 写入新缓存正确时序很重要✔ 先更新数据库 ✔ 再删除缓存如果反过来❌ 先删缓存 ❌ 再更新数据库可能出现线程A删缓存 线程B查数据库 → 写入旧数据到缓存 线程A更新数据库 缓存变成旧数据脏数据2️⃣ 延迟双删解决并发问题即使“先更新数据库再删缓存”在高并发下仍可能出问题。优化方案1. 更新数据库 2. 删除缓存 3. sleep(几百毫秒) 4. 再删除一次缓存作用 防止并发请求把旧数据重新写回缓存3️⃣ 设置过期时间TTL给缓存加过期时间SET key value EX60优点自动过期简单可靠缺点在过期前仍可能读到旧数据 通常作为兜底方案4️⃣ 主动更新缓存适用于强一致要求流程1. 更新数据库 2. 更新缓存适用场景数据结构简单一致性要求高如库存问题容易出现并发覆盖复杂系统难维护5️⃣ 使用消息队列保证一致性进阶结合 MQ如 Apache Kafka1. 更新数据库 2. 发送消息 3. 消费者更新/删除缓存优点解耦可重试最终一致性更可靠6️⃣ 订阅数据库变更Binlog方案高级架构中会用监听 MySQL binlog自动更新 Redis常见工具Canal阿里开源适合 大规模、高一致性系统三、工程实践推荐方案结论在大多数互联网系统中最佳实践是✅ Cache Aside 删除缓存 TTL具体策略写 更新数据库 删除缓存 读 先查缓存 没有再查数据库并写入缓存再加上✔ 过期时间TTL✔ 热点数据保护✔ 必要时延迟双删四、不同一致性要求的选择场景推荐方案一般业务删除缓存 TTL高并发热点数据延迟双删强一致如库存更新缓存 or 加锁大规模系统MQ / Binlog五、关键总结Redis 不保证强一致性只能做到最终一致性设计原则是优先保证数据库正确缓存只是“加速层”通过策略降低不一致时间窗口ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ ᅟᅠ