如何解决数据更新导致缓存一致性问题?
一.为什么使用分布式缓存
我们初步了解了什么是缓存以及一般的缓存使用逻辑,那么为什么要使用分布式缓存呢?
在服务架构初期我们基本上都是单体架构,一个tomcat服务器撑起一片天,可能只需要基于本地内存存储进行缓存即可。但随着架构的演进,由单体SOA架构闫金成分布式架构之后,如果还使用本地缓存,那么就会导致多台服务器上缓存不一致,数据无法共享问题。因此基于这种问题,分布式的缓存由此诞生。当前分布式缓存最常用的工具还是redis和memcached。
二.缓存过期以及一致性问题
读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容 易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。
讨论一致性问题之前,先来看一个更新的操作顺序问题:
先删除缓存,再更新数据库
问题:同时有一个请求 A 进行更新操作,一个请求 B 进行查询操作。 可能出现:
( 1)请求 A 进行写操作(key = 1 value = 2) ,先删除缓存 key = 1 value = 1
( 2)请求 B 查询发现缓存不存在
( 3)请求 B 去数据库查询得到旧值 key = 1 value = 1
( 4)请求 B 将旧值写入缓存 key = 1 value = 1
( 5)请求 A 将新值写入数据库 key = 1 value = 2
缓存中数据永远都是脏数据
我们比较推荐操作顺序:
先删除缓存,再更新数据库,再删缓存(双删,第二次删可异步延时)
public void write(String key,Object data){
redis.delKey(key);
db.updateData(data);
Thread.sleep(500);
redis.delKey(key);
}
接下来,看一看缓存同步的一些方案,见下图:
2.1.数据实时同步更新
方法:更新数据库同时更新缓存,使用缓存工具类和或编码实现。
优点:数据实时同步更新,保持强一致性
缺点:代码耦合,对业务代码有侵入性
2.2.数据准实时更新
准一致性,更新数据库后,异步更新缓存,使用观察者模式/发布订阅/MQ 实现;
优点:数据同步有较短延迟 ,与业务解耦
缺点:实现复杂,架构较重
2.3.缓存失效机制
弱一致性,基于缓存本身的失效机制
优点:实现简单,无须引入额外逻辑
缺点:有一定延迟,存在缓存击穿/雪崩问题
2.4.定时任务更新
最终一致性,采用任务调度框架,按照一定频率更新
优点:不影响正常业务
缺点:不保证一致性,依赖定时任务
2.5.各方案实现总结
方案名称技术特点优点缺点适用场景数据实时同步更新强一致性,更新数据库同时更新缓存,使用缓存工具类和或编码实现数据一致性强代码耦合 运行期耦合 影响正常业务数据一致实时性要求比较高的场景,如:银行业务、证券交易;数据准实时更新准一致性,更新数据库后,异步更新缓存,使用观察者模式/发布订阅/MQ实现;数据同步有较短延迟 与业务解耦 不影响正常业务实现复杂,架构较重不适合写操作频繁并且数据一致实时性要求严格的场景;缓存失效****机制弱一致性,基于缓存本身的失效机制实现简单有一定延迟 不保证强一致性 存在缓存雪崩问题;适合读多写少的场景,能接受一定数据延时;任务调度****更新最终一致性,采用任务调度框架,按照一定频率更新;不影响正常业务;不保证一致性 依赖定时任务 容易堆积垃圾数据;适合复杂统计类数据缓存更新,对数据一致实时性要求低的场景;如:统计类数据,BI分析等;
版权归原作者 王老狮 所有, 如有侵权,请联系我们删除。