Redis 缓存和数据库数据的一致性问题,就是 Redis 缓存的数据和数据库中保存的数据出现不相同的现象。导致这种现象的发生一般有两种情况:
- 在 Redis 缓存和数据库进行数据同步时出现了异常,导致数据同步失败
- 在高并发的情况下,有多个线程同时操作 Redis 缓存和数据库,导致数据不一致性
目前主流的方案有以下几种
方案1:同步删除
核心流程:
-
先更新数据库数据
-
然后删除缓存数据
存在的问题:
1)删除缓存失败存在脏数据
2)难以收拢所有更新数据库入口
使用同步删除方案,你必须在所有更新数据库的地方都进行缓存的删除操作,如果你有一个地方漏掉了,对应的缓存就相当于没有删除了,就会导致脏数据问题。
还有就是如果我们通过命令行直接来更新数据库的数据,或者通过公司提供的数据库管理平台来更新数据库数据,这个时候你就没法删除了,因为你的同步删除其实只是写在你的代码里面,这个时候也就导致脏数据问题了,这也是为什么说同步删除很难覆盖所有的入口,同时存在很大的风险。
3)并发场景下存在脏数据
例子:表A存在数据 a=1,并发情况下可能有以下流程:
时序 | 线程1 | 线程2 |
---|---|---|
1 | 查询数据库数据:a=1 | |
2 | 更新数据库:a=2 | |
3 | 删除缓存数据 | |
4 | 将数据写入缓存:a=1 |
上面的例子中,由于线程2在查询完数据库数据之后,写入缓存之前,数据库的数据被线程1更新并且执行完同步删除操作了,所以最终导致脏数据问题,并且脏数据可能会持续很久。
当然,由于更新数据库操作耗时一般比写缓存更久,所以该例子发生的概率并不会太大,但还是有可能的。
最典型的场景就是,线程2查询完数据库之后,写缓存之前,线程2所在服务器发生了YGC,这个时候线程2可能就需要等待几十毫秒才能执行写缓存操作,这种情况就很容易出现上面这个例子了。
小结:由于难以收拢所有更新数据库入口,同时可能存在长期的脏数据问题,该方案一般不会被单独使用
方案2:延迟双删
核心流程:
-
删除缓存数据
-
更新数据库数据
-
等待一小段时间
-
再次删除缓存数据
存在的问题:
1)延迟时间难以确认
到底是延迟一秒或者是几秒,这个其实很难确认,你总不能延迟几分钟吧,因为你如果延迟几分钟,那这几分钟可能就存在脏数据了,所以这个时间很难确定。
2)无法绝对保障数据的一致性
例子:表A存在数据 a=1,并发情况下可能有以下流程