缓存与数据库一致性方案
一、缓存更新策略概述
在现代分布式系统中,缓存作为数据库的前置层,能显著提升系统性能。然而,缓存与数据库之间的数据一致性是一个经典难题。以下是三种常见的缓存更新策略及其优缺点分析。
二、方案对比分析
方案一:直接更新策略
模式:
-
先更新数据库,再更新缓存
-
或先更新缓存,再更新数据库
问题分析:
-
并发更新场景下会出现数据竞态条件
-
示例时序问题:
请求A: 更新DB(value=2) → 更新缓存(value=2)
请求B: 更新DB(value=3) → 更新缓存(value=3)
可能结果:缓存最终为2(请求A覆盖了请求B)
解决方案:
-
采用分布式锁强制串行化
-
更新前获取锁,完成操作后释放
-
lock.acquire();
try {updateDB();updateCache();
} finally {lock.release();
}
优缺点:
-
✅ 缓存命中率高(始终更新最新值)
-
❌ 锁机制带来性能瓶颈
-
❌ 生产环境较少采用(复杂度高)
方案二:先删缓存后更新DB(Cache Aside)
执行流程:
-
删除缓存
-
更新数据库
并发问题:
1. 请求A删除缓存
2. 请求B读取缓存未命中,查询DB(old value)
3. 请求B写入缓存(old value)
4. 请求A更新DB(new value)
结果:缓存与DB不一致
解决方案:
-
延迟双删策略:
-
第一次删除缓存
-
更新数据库
-
等待一定时间(如500ms)
-
再次删除缓存
-
挑战:
-
延迟时间难以精确设定
-
二次删除可能失败
-
生产环境实施效果不理想
方案三:先更新DB后删缓存(推荐方案)
执行流程:
-
更新数据库
-
删除缓存
优势分析:
-
出现不一致的概率极低(需要满足同时满足:
-
缓存刚好失效
-
读请求在写请求DB更新前完成
-
读请求耗时超过写请求)
-
异常处理:
-
同步重试机制:
void updateData(Data newData) {try {db.update(newData);cache.delete(newData.id);} catch (Exception e) {// 重试逻辑for (int i = 0; i < 3; i++) {try {cache.delete(newData.id);break;} catch (Exception retryEx) {if (i == 2) alertAdmin();}}}
}
-
异步补偿方案:
-
通过消息队列实现最终一致性
-
架构示例:
业务服务 → DB → Binlog → MQ → 消费者删除缓存
三、生产环境最佳实践
基础方案
-
采用"先更新DB,后删缓存"
-
实现同步删除重试(3次左右)
-
设置监控告警机制
进阶方案(推荐)
基于Binlog的异步删除:
-
技术组件:
-
MySQL + Canal/Alibaba Debezium
-
RocketMQ/Kafka
-
缓存服务
-
-
工作流程:
复制
下载
DB变更 → Canal监听Binlog → MQ投递 → 消费者处理缓存删除
优势:
-
完全解耦业务逻辑
-
自动重试保证最终一致性
-
对主流程零影响
实施建议:
-
消息幂等处理:
void handleCacheDelete(Message msg) {if (deduplicationCache.exists(msg.id)) {return; // 已处理}cache.delete(msg.key);deduplicationCache.set(msg.id);
}
-
监控指标:
-
消息堆积量
-
处理延迟
-
失败率
四、特殊情况处理
缓存穿透保护
当采用删除策略时,需防范缓存击穿:
public Data getData(String id) {Data data = cache.get(id);if (data == null) {data = db.query(id);if (data != null) {// 设置较短的过期时间cache.set(id, data, 300); } else {// 空值缓存cache.set(id, NULL_VALUE, 60);}}return data == NULL_VALUE ? null : data;
}
热点数据特殊处理
对极高频率访问的数据:
-
采用永不过期策略
-
通过后台任务定期同步
-
变更时双写保证一致性
五、总结建议
-
中小型系统:
-
直接采用方案三(更新DB+删除缓存)
-
配合简单重试机制
-
-
大型分布式系统:
-
引入Binlog+MQ的异步方案
-
建立完善监控体系
-
-
关键业务数据:
-
可考虑短暂加锁保证强一致性
-
牺牲部分性能换取绝对准确
-
最终选择应权衡:
-
业务对一致性的要求级别
-
系统性能需求
-
团队技术储备
-
运维监控能力