缓存,从本质上讲,是为了更好的协调两个速度差异比较大的组件而引入的一种中间缓存层。例如,如果需要将数据读入CPU进行计算处理,由于CPU的运算速度是非常快的,而磁盘的IO处理相比于CPU来说,慢了很多数量级,每次从磁盘读取数据,势会造成CPU长时间并且频繁等待磁盘IO。此时,我们就可以通过内存来缓和CPU和磁盘之间的速度差异。
双写一致性方案:
1、先写数据库后写缓存:并发情况下,可能会出现两种情况。1、线程A先更新数据库、线程B再更新数据库,但是由于某些原因线程B先写入缓存,然后线程A再写入缓存。导致缓存中还旧数据与数据库数据不一致。2、线程A更新完数据库然后去更新缓存,但是由于某些原因导致缓存更新失败,那么数据库中还是老数据。解决:可以设置一个过期时间,但是不能完全解决。
2、先写数据库后删缓存:可能存在的问题:第一个操作成功但是第二个操作失败。
3、先删缓存后写数据库:删除缓存之后,立马有个线程来读然后又把数据库写入缓存中了,然后在更新数据库,还是会导致不一致问题,但是这个概率小了很多。同样可以设置缓存过期时间尽量避免长时间都是老数据。
4、延迟双删:变更数据库、先删缓存、延迟一会、在删除一次。也可能有问题,1、删除失败(还是会有老问题。我连不上这个redis但是别人能连上这个redis。导致还是老数据)。2、其他版本问题。那种极端情况概率非常小,因为redis是缓存,更新的数据极快不可能会在你删除缓存之后才更新完缓存。
注意:在分布式开发的时候引入redis缓存这一类要小心,就比如A做的这个微服务模块他想提高读效率,加了一个redis,他也尽量保证了数据库缓存一致性,但是他只是在他自己这个模块保证了。B是另一个模块的开发人员,他不知道A引入了Redis,就不会去对redis去操作。导致数据库缓存不一致。
理解一句话:缓存是数据库的缓存,他们应该是一体的,不是某个模块的。