场景
我们在很多情况下会使用缓存提高查询效率,减小数据库压力。但是引入缓存后,就要面对如何保证缓存与DB数据一致性的问题。在讨论以下方案前,得先明白任何方案都不是百分百可靠且适用你的,要依据业务场景做出选择。
解决方案
- 先更新/删除缓存,再更新DB
- 先更新DB,再更新/删除缓存
- 延迟双删
- 先更新DB,再使用binlog日志+消息队列更新/删除缓存
先更新/删除缓存,再更新DB
如果先更新缓存,然后更新DB的动作失败,下一个请求获取到的依然是旧值,DB上的也是旧值,那么当缓存过期后,之前的更新操作完全失效就很奇怪了。
如果先更新缓存,再更新DB,下一个请求获取到的可能依然是旧值。
先更新缓存,再更新DB
先更新DB,再更新/删除缓存
如果先更新DB,然后操作缓存失败或出现并发,下一个请求获取到的依然是旧值,但是DB上是最新的,当缓存过期后,重新写入缓存的就是最新值。
如果先更新DB,再更新缓存,下一个请求获取到的可能依然是旧值。
先更新DB,再更新缓存.png
延迟双删
延迟双删是指在操作缓存后,再更新DB,等待一段时间后(一般要求大于一次缓存操作时间),再操作一次缓存。
但其实在并发的时候也可能出现在二次更新缓存后,有其他线程又将他更新成旧值。
先更新DB,再使用binlog日志+消息队列更新/删除缓存
使用消息队列的好处是自带了重试机制,增加了操作缓存成功率。对于复杂的缓存操作,也实现了解耦。但是复杂度也大大提升了,也提升运维成本,并且面对高并发,还会有性能问题。
删除缓存还是更新缓存
还有个容易让人纠结的问题是,如何操作缓存,是删除缓存还是更新缓存?
更新缓存
更新缓存最大的好处就是简单方便。
删除缓存
如果你是一个写入DB场景比较多,而读取DB场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
如果在写入缓存前,要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。
总结
综合各方面考量,最好的方案是使用分布式锁+延迟双删,在查询的时候加上分布式锁还有双重校验。现在大部分应用都实现了分布式锁,再加上数据库事务的使用,这已经解决了大部分的缓存一致性问题。以上讨论更重要的是帮大家总结归纳各个场景,以便大家更深层的研究。
网友评论