缓存双写一致性
- 对于读:先读缓存,缓存没有,再读ku,回写缓存,这种没啥说的。
- 对于写:先写库,再删除缓存,本文主要基于这种来探讨一下这样处理有什么问题?
如下图所示:
图中表示大量请求同时涌入,读数据和写数据请求同时执行,下面我们基于这幅图来剖析为何先写库,再删除缓存会有问题?
大前提:缓存正好失效
**正常情况:**有一个读数据和一个写数据请求同一时刻过来,读请求发现缓存失效,去读数据库(旧数据),然后回写缓存(旧数据),此时写请求也更新好了数据库,再把缓存删掉,这样的话即使之前读请求把旧值回写缓存也没事。
**问题的关键在于:**步骤3和步骤5谁先执行,在正常情况下,3都是先于5执行的,因为读库一定比写库快。可是高并发下就是会有不正常的情况,比如读数据接口和写数据接口是在两个不同的jvm中,并且读数据请求在步骤3的时候发生了FULL GC, 延迟了回写缓存的时间,导致缓存旧数据。
解决方案:
前提:一定设置缓存过期时间,如1小时
-
定时刷库:每一分钟取出数据库数据重新放到redis,需要额外线程池消耗,可以优化成当更新数据的时候把id封成延迟消息发送给MQ,由MQ去查库再回写缓存
-
延迟双删:更新数据的时候删除缓存后在开启一个定时器15s后再删除一次缓存,也可以把id封成延迟消息发送给MQ,由MQ去删除缓存,说到家了方案二和方案一很像。
-
分布式锁:在读写接口加分布式锁,让读写串行化。博客链接TODO
-
分布式乐观锁:博客链接TODO
-
分布式读写锁:因为大多数情况下,都是读请求,读读无并发还是可以提高不少相应速度的,博客链接TODO