Redis 缓存和数据库数据的同步问题
数据一致性问题
在使用缓存的时候,需要考虑缓存数据和数据库数据的一致性问题,常见的缓存更新方案有以下几种:
1. 先更新缓存,再更新数据库
-
可能出现的问题:若缓存更新成功、数据库更新失败,导致缓存和数据库数据不一致,且不好排查问题
-
结论:不采用
2. 先更新数据库,再更新缓存
-
可能出现的问题:
-
若数据库更新成功、缓存更新失败,导致缓存和数据库数据不一致,且不好排查问题
-
存在并发问题
线程 1 先执行,执行过程中线程 2 执行并执行完成,此时会出现数据库中为 B、缓存中为 A 的数据不一致情况
-
-
结论:不采用
3. 先删除缓存,再更新数据库
-
可能出现的问题:
线程 1 先执行,删除了缓存,还未更新数据库的值 A,只是线程 2 执行,发现缓存不存在,于是从数据中查询到当前的值 B,并且更新到缓存中,此时线程 1 继续执行,将数据库的值更新为 A,此时会出现数据库中为 A、缓存中为 B 的数据不一致情况
-
结论:若采用,需要进行延时双删操作,更新数据库成功后删除读请求可能产生的脏缓存,步骤如下
- 先删除缓存
- 再更新数据库
- 适当延时后(预估读请求的执行耗时),再次删除缓存
4. 先更新数据库,再删除缓存
这种方式被称为 Cache Aside Pattern,读的时候先读缓存,缓存没有的话就读数据库,然后取出数据后放入缓存,同时返回响应,更新的时候先更新数据库,然后再删除缓存
-
可能存在的问题:
当缓存失效时,线程 1 查询数据库中的值为 A,再更新缓存之前线程 2 开始执行,将数据库中值更新为 B,然后线程 2 删除缓存,之后线程 1 恢复执行,将缓存更新为 A,此时会出现数据库中为 B、缓存中为 A 的数据不一致情况
-
结论:可以采用。因为上述不一致场景出现的条件非常苛刻,首先缓存必须为失效状态,其次线程 1 中的读操作的速度必须慢于线程 2 中的写操作,但数据库中读的速度是远快于写,所以此方案可以满足绝大多数业务场景。