咱们从近期代码评审过程当中的一段代码,开始探讨缓存和数据库的一致性问题。html
通常来讲,使用缓存主要为了提高应用性能和下降DB的直接负载,从场景上来讲能够接受最终一致性方案, 若是业务场景要求 “缓存+数据库” 必须保持强一致性的话,那么须要使用同步方案,好比排它锁或者队列机制+数据库事务处理 这样的话影响系统可用性,简单状况下可使用....仍是另选方案吧java
public Ware getById(long id) {
Ware ware = Cache.get(id);
if (ware != null) {
return ware;
}
ware = Db.get(id);
if(ware != null){
//缓存时间12小时,根据具体业务调整
Cache.put(ware,60*60*12);
}
return ware;
}
public void update(Param param) {
Db.update(param);
Cache.del(param.getId());
}
//Cache
public void del(long id) {
//异常 静默
CacheClient.expire("key1"+id, 0);
CacheClient.expire("key2"+ id, 0);
}
复制代码
先说说这段代码已经考虑到的问题,也是使用Cache Aside Pattern的好处git
A: 1. 考虑到 update 方法自己并发执行,Db.update和Cache.update不是原子操做,会出现先更新DB的后更新cache 时序不一致问题(库存修改存在并发状况,并要求时序一致性)github
A: 2. 商品的缓存数据可能包含多维度好比库存和价格,这儿更新了库存一个字段,若是更新缓存须要查询多表数据聚合放置缓存shell
A: 3. 这次更新的商品可能不被查询使用,好比冷数据,采用查的时候缓存起到了懒加载效果数据库
A: 4. 缓存击穿问题,这儿的更新是基于单个商品,通常状况可忽略,请求量若是特别高,好比秒杀商品须要更改缓存结构和特殊的处理方式(好比版本替换机制,队列扣减机制等等,后续有机会bob再详解...)缓存
未考虑到的问题架构
看到最后咱们能够发现与其说是保证了一致性,不如说咱们是在 提升缓存一致性并发
从上面的业务使用场景结合问题分析,咱们也能够看出在不一样的场景下为了达到不一样的效果(一致性要求、吞吐、并发)咱们有不一样的方案,这些方案的选择离不开场景,但同时咱们也要结合技术复杂度和团队技术水平、开发维护成本综合考虑来选择适合团队的方案。异步
高并发架构系列:Redis缓存和MySQL数据一致性方案详解