相信大家偶尔都会遇到缓存和数据库不一致的问题。今天就来聊聊这个话题。为什么数据库主从不一致?我们先回顾一下,没有缓存时,数据库主从不一致。如上图所示,发生的场景是写后立即读:(1)主库的写请求(主从还没有同步);(2)从库发出读请求,读取旧数据;(3)最后,master和slave同步完成;结果是在活动同步完成之前将读取旧数据。可以看出主从不一致的影响时间很短,主从同步完成后才会读取新的数据。什么时候缓存和数据库不一致?再看,引入缓存后,缓存和数据库是不一致的。如上图,出现的场景也是,先写后读:(1+2)先写一个请求,清除缓存,写入数据库;(3+4+5)紧跟着一个读请求,读缓存,缓存未命中,从库中读,写缓存放数据,这样后续读可以缓存命中(主从同步未完成,放旧数据在缓存中);(6)最后完成主从同步;结果是:旧数据放入Cache,即使主从同步完成,还是会从缓存中读取旧数据。可以看出,加入缓存后,产生的不一致会影响很长时间,最终达不到一致性。为什么会出现这种不一致呢?可见,这里所说的缓存和数据库数据不一致,根本上是数据库主从不一致造成的。主库发生写操作后,在从库的binlog同步时间间隔内,读请求可能会导致旧数据被缓存。如果不能彻底解决主从不一致,引入缓存后,在binlog同步区间内,旧数据不可避免。但是,有没有办法让即使引入缓存,不一致性也不会比“不缓存”更糟呢?这是一个更现实的优化目标。思路转化为:从库同步完成后,如果缓存中有旧数据,要及时淘汰旧数据。缓存和数据库不一致,如何优化?如上图所示,并发读写导致脏数据读入缓存后:(6)主从同步;(7)通过工具订阅从库的binlog,这里可以最准确的知道从库数据同步完成的时间;画外音:这张图的订阅工具是DTS,可以cannal,也可以自己订阅分析binlog。(8)从库执行写操作后,再次向缓存发起删除,将这段时间可能写入缓存的旧数据剔除;这样一来,至少可以保证引入缓存后,主从不一致,这不比不引入缓存更糟。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
