缓存更新策略
先更新数据库,再更新缓存
缺点:
1)、线程安全角度,同时有请求A和请求B进行更新操作,那么会出现
a.线程A更新了数据库
b.线程B更新了数据库
c.线程B更新了缓存
d.线程A更新了缓存
这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。
2)、业务场景角度,如果写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
先删除缓存,再更新数据库
缺点:
(1)请求A进行写操作,删除缓存
(2)请求B查询发现缓存不存在
(3)请求B去数据库查询得到旧值
(4)请求B将旧值写入缓存
(5)请求A将新值写入数据库
以上情况,可能会出现脏数据。
解决方案:
延时删除策略:
(1)先淘汰缓存(2)再写数据库(这两步和原来一样)(3)休眠1秒或其他时间,再次淘汰缓存
先更新数据库,再删除缓存
缺点:
a.缓存刚好失效
b.请求A查询数据库,得一个旧值
c.请求B将新值写入数据库
d.请求B删除缓存
e.请求A将查到的旧值写入缓存
以上情况,可能会出现脏数据。但是概率极低,因为一般 c 的写耗时高于 b 的读耗时,就很难出现 d 在 e 前面。
解决方案:
1.延时删除策略:
(1)先淘汰缓存(2)再写数据库(这两步和原来一样)(3)休眠1秒或其他时间,再次淘汰缓存
2.重试机制:
将删除失败的key发送至消息队列,自己消费消息,重试删除,直到成功。对业务代码有入侵。
热点key的重建优化
互斥锁
当发现key过期需要重建时,加锁执行重建逻辑,避免高并发导致的过多重建次数。
永不过期
热点key,设置为没有过期时间,但是在逻辑上设置过期时间,即在value上加个过期时间的字段,每次查询时,发现逻辑时间过期的话,就使用异步线程去重建缓存。可能会存在短暂时间内的数据不一致。
未完待续……