一致性等级与缓存更新策略详解
⭐一致性的级别
1. 强一致性
- 任何时间点系统所有节点看到的数据一致
- 写入后立即同步到数据库
- ✅ 优点:一致性强
- ❌ 缺点:写入性能低
- 🎯 适用场景:金融交易、在线支付等强一致性需求的场景
2. 弱一致性
- 写入后,不同节点看到的数据可能不同
- 数据同步存在延迟
- ✅ 优点:性能高
- ❌ 缺点:可能存在短时间不一致
- 🎯 适用场景:社交网络、新闻评论等对一致性要求不高的系统
3. 最终一致性
- 系统最终会达到一致状态,但中间可能存在短暂不一致
- ✅ 优点:写入性能高
- ❌ 缺点:无法保证实时一致性
- 🎯 适用场景:CDN、推荐系统等可容忍延迟一致的业务
⭐缓存更新策略
同步顺序分类
- 先更新缓存,再更新数据库
- 先更新数据库,再更新缓存
- 先删除缓存,再更新数据库 ✅(推荐)
- 先更新数据库,再删除缓存 ✅(常见)
⭐ 更新 vs 删除
更新缓存方式
- ✅ 优点:命中率高,及时性强
- ❌ 缺点:计算复杂、资源浪费
- 🎯 适合:数据频繁使用,计算不复杂
删除缓存方式(最常用)
- ✅ 优点:简单通用,不依赖数据结构
- ❌ 缺点:可能导致缓存穿透
- 🎯 适合:低频更新业务
⭐ 先删除缓存,再更新数据库
问题场景
- 缓存刚删,数据库还没更新成功
- 此时其他线程读取旧数据并写入缓存
- 更新成功后写入的数据被旧数据覆盖 ➡ 不一致
延迟双删方案
步骤:
- 删除缓存
- 更新数据库
- 延迟 N 秒
- 再次删除缓存 ✅
问题与优化
- 更新线程吞吐下降 ➡ 使用 异步淘汰机制
- 第二次删除失败 ➡ 使用 重试机制
⭐ 先更新数据库,再删除缓存
极限不一致情况:
- A线程读缓存未命中,准备查库
- B线程更新数据库并删除缓存
- A线程读的是旧数据并写入缓存 ➡ 数据回滚
⭐ 最终一致性策略
消息队列方案
- 更新数据库后发送消息到 MQ
- 缓存更新操作异步消费 MQ 完成更新
- 中间过程允许短时间缓存不一致
🎯 适用:非强一致需求,如推荐商品
扩展:写失败记录入 MQ
- 更新失败 ➡ 入队重试处理
⭐ Binlog 日志监听方案
- 基于 MySQL 主从复制
- 监听 binlog 日志变化同步缓存
- ✅ 无侵入,耦合低
⭐ 强一致性实现方式
1. 串行化写入(消息队列)
- 所有写操作进入 MQ 排队处理
- 当前写未完成前其他写操作不执行
- 设置超时 ➡ 防止阻塞
2. 分布式锁
写请求流程:
- 获取锁
- 删除缓存 + 更新数据库
- 释放锁
读请求流程:
- 读取缓存,命中返回
- 未命中获取锁:
- 成功:读库 ➕ 设置缓存 ➕ 释放锁
- 失败:直接读库(说明其他线程在写)
✅ 支持自动续期(如 redisson)
⭐ 基于开关控制
写请求:
- 打开写操作开关 ➡ 拦截读
读请求:
- 检查写操作标志 ➡ 读库或缓存
异步恢复机制:
- 写失败 ➡ 标记恢复任务 ➕ 异步执行修复
如你觉得本文有价值,欢迎点赞 👍、收藏 ⭐、评论 💬
我将持续分享更多关于微服务架构、缓存一致性与系统设计的干货内容!