一致性等级与缓存更新策略详解

94 阅读3分钟

一致性等级与缓存更新策略详解

⭐一致性的级别

1. 强一致性

  • 任何时间点系统所有节点看到的数据一致
  • 写入后立即同步到数据库
  • ✅ 优点:一致性强
  • ❌ 缺点:写入性能低
  • 🎯 适用场景:金融交易、在线支付等强一致性需求的场景

2. 弱一致性

  • 写入后,不同节点看到的数据可能不同
  • 数据同步存在延迟
  • ✅ 优点:性能高
  • ❌ 缺点:可能存在短时间不一致
  • 🎯 适用场景:社交网络、新闻评论等对一致性要求不高的系统

3. 最终一致性

  • 系统最终会达到一致状态,但中间可能存在短暂不一致
  • ✅ 优点:写入性能高
  • ❌ 缺点:无法保证实时一致性
  • 🎯 适用场景:CDN、推荐系统等可容忍延迟一致的业务

⭐缓存更新策略

同步顺序分类

  1. 先更新缓存,再更新数据库
  2. 先更新数据库,再更新缓存
  3. 先删除缓存,再更新数据库 ✅(推荐)
  4. 先更新数据库,再删除缓存 ✅(常见)

⭐ 更新 vs 删除

更新缓存方式

  • ✅ 优点:命中率高,及时性强
  • ❌ 缺点:计算复杂、资源浪费
  • 🎯 适合:数据频繁使用,计算不复杂

删除缓存方式(最常用)

  • ✅ 优点:简单通用,不依赖数据结构
  • ❌ 缺点:可能导致缓存穿透
  • 🎯 适合:低频更新业务

⭐ 先删除缓存,再更新数据库

问题场景

  1. 缓存刚删,数据库还没更新成功
  2. 此时其他线程读取旧数据并写入缓存
  3. 更新成功后写入的数据被旧数据覆盖 ➡ 不一致

延迟双删方案

步骤:

  1. 删除缓存
  2. 更新数据库
  3. 延迟 N 秒
  4. 再次删除缓存 ✅
问题与优化
  • 更新线程吞吐下降 ➡ 使用 异步淘汰机制
  • 第二次删除失败 ➡ 使用 重试机制

⭐ 先更新数据库,再删除缓存

极限不一致情况:

  1. A线程读缓存未命中,准备查库
  2. B线程更新数据库并删除缓存
  3. A线程读的是旧数据并写入缓存 ➡ 数据回滚

⭐ 最终一致性策略

消息队列方案

  1. 更新数据库后发送消息到 MQ
  2. 缓存更新操作异步消费 MQ 完成更新
  3. 中间过程允许短时间缓存不一致

🎯 适用:非强一致需求,如推荐商品

扩展:写失败记录入 MQ

  • 更新失败 ➡ 入队重试处理

⭐ Binlog 日志监听方案

  • 基于 MySQL 主从复制
  • 监听 binlog 日志变化同步缓存
  • ✅ 无侵入,耦合低

⭐ 强一致性实现方式

1. 串行化写入(消息队列)

  • 所有写操作进入 MQ 排队处理
  • 当前写未完成前其他写操作不执行
  • 设置超时 ➡ 防止阻塞

2. 分布式锁

写请求流程:
  1. 获取锁
  2. 删除缓存 + 更新数据库
  3. 释放锁
读请求流程:
  1. 读取缓存,命中返回
  2. 未命中获取锁:
    • 成功:读库 ➕ 设置缓存 ➕ 释放锁
    • 失败:直接读库(说明其他线程在写)

✅ 支持自动续期(如 redisson)


⭐ 基于开关控制

写请求:

  • 打开写操作开关 ➡ 拦截读

读请求:

  • 检查写操作标志 ➡ 读库或缓存

异步恢复机制:

  • 写失败 ➡ 标记恢复任务 ➕ 异步执行修复

如你觉得本文有价值,欢迎点赞 👍、收藏 ⭐、评论 💬
我将持续分享更多关于微服务架构、缓存一致性与系统设计的干货内容!