Redis双写一致性问题
1、缓存的最终一致性从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。因此,接下来讨论的思路不依赖于给缓存设置过期时间这个方案。2、数据更新策略(1)先更新数据库,再更
1、缓存的最终一致性
从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。因此,接下来讨论的思路不依赖于给缓存设置过期时间这个方案。
2、数据更新策略
(1)先更新数据库,再更新缓存(不可行)
存在问题:1)当写操作十分频繁的情况下,可能用户根本就没有去读缓存数据就又频繁更新了,无疑是浪费性能的。
2)如果你的数据并不是直接写入缓存的,而是经过一系列计算再存入数据库的,那么频繁更新缓存同时还浪费了主业务服务器的性能。
3)极容易造成数据不一致情况
(2)先删除缓存,再更新数据库(推荐)
伪代码
public void write(String key,Object data){
redis.delKey(key);
db.updateData(data);
Thread.sleep(1000);
redis.delKey(key);
}
为了解决上述问题,采用延时双删策略,就是在更新完数据库后,睡眠一定时间,再次进行删除。
为什么要延时?
假设一个场景:Redis缓存中并没有这个数据,而在更新这个数据时,有个查询请求进来了,这个请求查取到旧的数据放入内存中,但是还没有写入到redis中,这是更新已经完成,且执行了第二次redis缓存删除,之后内存的旧数据被写入到了redis中,造成了redis和数据库数据不一致。
所以需要延时从内存写入redis缓存的时间,如果数据库做了读写分离,还需要缓存从主库同步到从库的时间。
吞吐量降低? 我们可以将第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,再返回。这么做,加大吞吐量。
(3)先更新数据库,再删除缓存
这种方案看上诉为什么要延时? 图解,如果redis中缓存正好过期,则可能会发生上图情况,此时我们也可以用延时来解决问题。
与(2)不同的是,(3)方案不会先去删除redis中缓存,如果缓存在正好过期,相当于先删除了redis缓存,就会存在上述的数据不一致问题,同样用延时删除解决。
(2)(3)方案中如果删除缓存失败怎么办? 删除失败,利用消息队列实现重试,设置重试次数,如果一直失败,只能靠redis的过期机制达到最终一致性。这里的删除最好是自己起一个线程,异步删除,保证业务不阻塞,正常运行。
更多推荐
所有评论(0)