一般来说,是淘汰。
是先操作缓存,还是先操作DB?
先操作缓存,再操作DB
先淘汰缓存成功,后更新DB失败(比如说服务挂了),不会造成不一致。
但是缓存淘汰了以后,主库还没有同步到从库,又有一个读请求,把旧的数据读到缓存,也会造成不一致。
这种情况下不一致概率是比较高的,因为一般情况下读请求远远高于写请求,当淘汰了缓存之后,在更新DB之前很有可能有读请求把从库的旧数据读到缓存中,从而造成不一致。
不过对于这种情况,有以下两种办法:
但是这样子代价就比较高了,架构变得复杂。
先操作DB,后操作缓存
先更新DB,后更新缓存。 假如更新完DB后,服务挂了,没有更新缓存,缓存过期后,经历一次缓存miss,那么数据将达到最终一致。
缓存与数据库不一致
如上图,发生的场景也是,写后立刻读:
(1+2)先一个写请求,淘汰缓存,写数据库
(3+4+5)接着立刻一个读请求,读缓存,cache miss,读从库,写缓存放入数据,以便后续的读能够cache hit(主从同步没有完成,缓存中放入了旧数据)
(6)最后,主从同步完成
导致的结果是:旧数据放入缓存,即使主从同步完成,后续仍然会从缓存一直读取到旧数据。
可以看到,加入缓存后,导致的不一致影响时间会很长,并且最终也不会达到一致。
如上图所述,在并发读写导致缓存中读入了脏数据之后:
(6)主从同步
(7)通过工具订阅从库的binlog,这里能够最准确的知道,从库数据同步完成的时间
画外音:本图画的订阅工具是DTS,也可以是cannal订阅和分析binlog
(8)从库执行完写操作,向缓存再次发起删除,淘汰这段时间内可能写入缓存的旧数据
(这样子还是在短时间内可能存在缓存和DB不一致,但是能达到最终一致性)
Cache Aside Pattern是缓存经典实践方式,分为读实践、写实践。
对于读请求
对于写请求