Redis和Mysql如何保证数据一致性
1. 导致数据不一致的原因
当数据发生变化的时候,需要同时去更新Redis和Mysql,更新数据是有先后顺序的,在极端情况下就会出现数据一致性的问题。
1. 先更新数据库再更新缓存
如果先更新数据库,若是缓存中的数据更新失败,就会出现数据库和redis中的数据不一致问题
2. 先删除缓存,再更新数据库
先删除缓存再更新数据库,在理想情况删除了缓存,更新了数据库,再第二次请求的时候会发现缓存是空的,会去读取数据库将数据缓存起来。
但是
删除缓存和更新数据库不是一个原子操作,若是缓存删除了,此时,第二条线程抢到CPU时间轮片,开始读取数据,发现没有缓存,查询数据库,并将数据缓存起来,此时第一条线程拿到CPU时间轮片,开始更新数据库,这个情况下会导致数据库和缓存不一致
采用最终一致性的方案解决
1. 采用延迟双删除的策略
具体步骤
- 先删除缓存
- 写入数据库
- 休眠500毫秒(视情况而定)
- 再次删除缓存
具体实现
public void write(String key,Object data){
redis.delKey(key); // 删除缓存
db.updateData(data); // 更新数据库
Thread.sleep(500); // 睡眠延迟
redis.delKey(key);// 再次删除缓存
}
2. 异步更新缓存(基于订阅Binlog)
读取MysqlBinlog日志后分析,利用消息队列,推送更新到redis缓存中,这样一旦产生了新的写入,更新,删除等操作,就可以把相关的更新推送到redis中
其实这种机制类似于Mysql的主从备份,Mysql的主从备份也是通过Binlog来实现数据一致性
这里的消息推送工具可以使用Kafka、rabbitMQ等消息队列来实现
结合使用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅
因为是最终一致性,所以业务如果无法接收短期不一致性的话就得更换策略