原文:https://learnku.com/articles/25012
前言
周所周知,在项目性能优化、提升的时候,我们引进了一个缓存的概念,即一款缓存数据的技术,项目在最初期架构规划时都会引进的一个组件。使用缓存有很多好处:加快请求的响应速度、减少数据库的交互与浪费大量的 IO 操作等,但是在某些场景下使用缓存也有可能会造成雪崩、穿透、数据不一致等问题,我们研究下使用缓存会导致有哪些数据不一致的情况发生以及在哪些场景会使用哪些具体的解决方案,首先我们必然还是会使用缓存的。
缓存更新策略
先更新数据库再更新缓存
-
浪费资源
每次去更新数据库再更新缓存都是需要申请 CPU 进行数据库的修改的,同时倘若数据的修改比较频繁以及数据的读操作却又比较少的时候,这种策略会导致出现冷数据的情况。 -
数据脏读
如果两个操作同时对数据进行操作时,举个栗子:线程 A 在线程 B 更新数据库成功后、更新缓存成功之前读取到数据,也就是读取到了缓存的旧数据。
该策略比较适合更新的频次比较少的场景下,比如博客的文章、基础数据、个人信息等场景。
先更新数据库再删除缓存
- 数据脏读
一个请求处理中过程中,倘若数据库更新成功了但是缓存更新失败了,那么后面的请求读取的数据都是旧数据、则脏数据。可以通过缓存过期时间定义缓存的有效期 (推荐),或者使用消息队列在删除缓存失败的时候再次异步更新缓存,直到成功为止,这两种方案都是尽可能减少读取脏数据的方案,还有一种方案可以完全解决数据脏读,就是异步请求串行化,一个字锁,但是会增加业务处理的时间甚至会出现死锁的情况。
这种缓存操作的策略使用的情况被使用的比较多、使用的场景也比较广泛。
先删除缓存再更新数据库
- 数据脏读
与第二种情况类似,但是更容易出现数据脏读,比如:删除缓存失败更新数据库成功 (一般的业务可能在缓存修改失败后不再进行数据库的更新了)、线程 B 读取了线程 A 已经成功删除了缓存后更新数据库之前读取了脏数据并且也导致缓存的数据也是旧数据。解决方案还是使用缓存过期时间或者消息队列,在缓存过期的时候务必要注意雪崩的问题,比如大批量数据的过期时间几乎集中在同一个时间点上,容易造成雪崩。