图文讲解Redis延时双删原因及必要性

目录

一、前言

二、常见更新策略

2.1 先删缓存,再更新数据库

2.2 先更新数据库,再删除缓存

2.3 普通双删

2.4 延迟双删

三、建议

一、前言

我们在实际项目中经常会使用到Redis缓存用来缓解数据库压力,但是当更新数据库时,如何保证缓存及数据库一致性,一般我们采用延时双删策略。

目前系统中常用的做法是一个查询接口,先查询Redis,如果不存在则查询数据库,并将结果放入到Redis中。

为什么是删除缓存,而不是更新缓存呢?主要是如果缓存的内容是带有树型结构或者List,Map,那么更新其中一个内容相对较慢。

本文所讲操作,均是按照如果缓存不存在,查询数据库后,再放入Redis。

二、常见更新策略

2.1 先删缓存,再更新数据库

如图:

图文讲解Redis延时双删原因及必要性_第1张图片

1、线程A删除缓存数据,此时还没更新数据库 

2、线程B查询缓存没有数据,查询数据库还是旧数据,放入缓存

3、线程C及其他线程使用旧缓存数据,缓存和数据库不一致

2.2 先更新数据库,再删除缓存

图文讲解Redis延时双删原因及必要性_第2张图片

1、线程A更新数据库,此时还没有删除缓存

2、线程B及其他线程此时使用的还是旧缓存数据,和数据库内容不一致

2.3 普通双删

图文讲解Redis延时双删原因及必要性_第3张图片

1、线程A先删除缓存,再更新数据库,再删除缓存

2、线程B查询缓存没有数据,在线程A更新数据库之前,查询到旧数据,此时系统时间片切换到线程A执行删除缓存,之后又轮到线程B放入缓存旧数据

3、线程C针对于线程A,查询缓存没有数据,查询到旧数据,放入缓存旧数据

都不能满足缓存和数据一致性。

2.4 延迟双删

图文讲解Redis延时双删原因及必要性_第4张图片

1、线程A先删除缓存,之后更新数据库

2、线程B和线程C发现缓存没数据,查询数据库。线程B查询到的是旧数据,线程C查询到的是新数据。之后纷纷放入缓存

3、线程A延时3-5秒(时间一般要大于SQL执行时间+线程切换执行时间100ms足够),再将缓存删除。之后其他线程再查询缓存,发现没数据,再次查询数据库及放入缓存都是新数据

极端情况就是线程D,所以延时双删还是不一定能保证缓存及数据一致。

三、建议

1、在发现缓存没有数据后,在执行查询数据库前,对该Key进行加锁,查询数据库并放入缓存后再解锁,这样可以避免缓存击穿问题,当某个redis数据不存在时,大量线程并发查询数据库。

2、在需要执行双删前,对该Key进行加锁,之后执行删除缓存,更新数据库,放入新数据到缓存,在解锁。保证缓存和数据一致性。

3、加锁的Key都需要设置过期时间,避免因为宕机造成死锁。

你可能感兴趣的:(中间件,redis,数据库,缓存)