redis缓存和数据库一致性问题及解决方案

根据当前计算机系统的三层储存架构,cpu缓存,内存,磁盘,我们日常开发通常会模仿这三层储存架构而在数据库之上添加机器本地缓存及redis缓存,既然涉及到了多个储存系统,那么必然就有数据一致性问题。

根据redis缓存的使用,可以分成2种情况:只读缓存和读写缓存

1.只读缓存

当系统收到get请求,则查询redis,redis有数据则返回,无数据则查询数据库,查到之后,写入缓存,以便于以后的请求使用。至于写请求,直接操作数据库。这样做的好处就是,保证了最新数据都在数据库中,而数据库是有可靠性保障的。

2.读写缓存

写请求也会发送到redis,得益于redis的高性能,写请求能快速完成,但是如果数据没有写入数据库,便发生宕机或者掉电,那么会发生数据丢失,给业务带来风险。所以通常会有两种回写策略。

2.1同步回写

由于数据库和redis的速度差异,同步回写会降低系统的响应速度。

2.2异步回写

所有的写操作先在缓存中更改,优先考虑系统响应,同样的,reids的宕机或者掉电则会导致数据丢失。

3.数据一致性

分为两种情况,一是 缓存中有数据,则必须与数据库中的数据一致;二是 缓存中没数据,则数据库中的数据必须是最新的。

对于读写缓存而言,根据具体场景对一致性的要求,选择同步或者异步回写。

对于读缓存而言,数据的一致性的复杂程度,主要发生在数据的删除和修改,新增的话,直接操作数据库,故无一致性问题。

3.1删除和修改数据

第一种情况:我们先删除缓存,在更新数据库,潜在的问题:数据库更新失败了,get请求进来发现没缓存则请求数据库,

导致缓存又刷入了旧的值。

第二种情况:我们先更新数据库,再删除缓存,潜在的问题:缓存删除失败,get请求进来缓存命中,导致读到的是旧值

3.2先删除缓存再更新数据库

假设有2个线程A和B,A删除缓存之后,由于网络延迟,在更新数据库之前,B来访问了,发现缓存未命中,则去请求数据库然后把旧值刷入了缓存,这时候姗姗来迟的A,才把最新数据刷入数据库,导致了数据的不一致性

3.2.1延迟双删

我们可以在A更新完数据库之后,sleep一会,再删一次缓存,需要注意的是,你要sleep到线程B把旧值刷到了缓存里面你再醒来把缓存删了,不然就会又被线程B把旧的值刷进去,所以需要预估读缓存和写缓存的时间以此确认应当sleep多久

3.3先更新数据库再删除缓存

这种场景潜在的风险就是更新完数据库,删缓存之前,会有部分并发请求读到旧值,这种情况对业务影响较小,我们通过重试机制,保证缓存能得到删除

你可能感兴趣的:(redis缓存和数据库一致性问题及解决方案)