一:缓存一致性
问题:缓存里面的数据如何和数据库当中的保持一致?
1.双写模式——数据库修改以后,将缓存中数据也修改一下
1)缺点:有可能产生脏数据。但是可以保证最终一致性。
2)解决方案:
- 加锁
- 暂时性数据不一致,为缓存数据加上过期时间
2.失效模式——删除掉缓存,等待下一次主动查询进行更新
1)缺点:会读到脏数据。第二个写如果进行的比较慢,就会导致第三个读,读到第一个写的脏数据
2)解决方案:
- 经常修改的数据,就不要加入缓存了,直接放进数据库。
二:缓存一致性-解决方案
1.无论是双写模式还是失效模式,都会导致缓存的不一致问题。即多个实例同时更新会出事。怎么办?
- 1、如果是用户纬度数据(订单数据、用户数据),这种并发几率非常小,不用考虑这个问题,缓存数据加 上过期时间,每隔一段时间触发读的主动更新即可
- 2、如果是菜单,商品介绍等基础数据,也可以去使用canal订阅binlog的方式。
- 3、缓存数据+过期时间也足够解决大部分业务对于缓存的要求。
- 4、通过加锁保证并发读写,写写的时候按顺序排好队。读读无所谓。所以适合使用读写锁。(业务不关心 脏数据,允许临时脏数据可忽略);
2.总结:
- 我们能放入缓存的数据本就不应该是实时性、一致性要求超高的。所以缓存数据的时候加上过期时间,保 证每天拿到当前最新数据即可。
- 我们不应该过度设计,增加系统的复杂性
- 遇到实时性、一致性要求高的数据,就应该查数据库,即使慢点。
3.获取商品服务代码
public Map<String, List<Catalog2Vo>> getCatalogJsonFromDbWithRedissonLock() {
//1.注入redisson,获取分布式锁。锁的名字,锁的粒度越细,速度越快
//锁的粒度:具体缓存的是某个数据,11号商品
RLock lock = redisson.getLock("catalogJson-lock");
lock.lock();
Map<String, List<Catalog2Vo>> dataFromDb = null;
try {
dataFromDb = getDataFromDb();
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
return dataFromDb;
}
三:缓存一致性-解决-Canal
Canal:阿里开源的中间件,可以模拟是一个数据库的从服务器。mysql有什么变化就会通过binlog二进制日志同步到cannal,canal会更新redis里的数据。
目前系统暂不使用canal,需要额外去维护。
四:我们系统一致性解决方案
1)缓存所有的数据都要有过期时间,数据过期下一次查询就能触发主动更新
2)读写数据的时候,加上分布式的读写锁
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84103.html