快取與資料庫不一致,咋辦?

58沈劍發表於2018-11-06

快取與資料庫的操作時序,不管是《Cache Aside Pattern》中的方案,還是《究竟先操作快取,還是資料庫?》中的方案,都會遇到快取與資料庫不一致的問題。今天聊聊這個問題。

一、資料庫主從不一致

先回顧下,無快取時,資料庫主從不一致問題。

如上圖,發生的場景是,寫後立刻讀:

(1)主庫一個寫請求(主從沒同步完成)

(2)從庫接著一個讀請求,讀到了舊資料

(3)最後,主從同步完成

導致的結果是:主動同步完成之前,會讀取到舊資料。

可以看到,主從不一致的影響時間很短,在主從同步完成後,就會讀到新資料。

二、快取與資料庫不一致

再看,引入快取後,快取和資料庫不一致問題。

如上圖,發生的場景也是,寫後立刻讀:

(1+2)先一個寫請求,淘汰快取,寫資料庫

(3+4+5)接著立刻一個讀請求,讀快取,cache miss,讀從庫,寫快取放入資料,以便後續的讀能夠cache hit(主從同步沒有完成,快取中放入了舊資料)

(6)最後,主從同步完成

導致的結果是:舊資料放入快取,即使主從同步完成,後續仍然會從快取一直讀取到舊資料。

可以看到,加入快取後,導致的不一致影響時間會很長,並且最終也不會達到一致。

三、問題分析

可以看到,這裡提到的快取與資料庫資料不一致,根本上是由資料庫主從不一致引起的。當主庫上發生寫操作之後,從庫binlog同步的時間間隔內,讀請求,可能導致有舊資料入快取。

假如主從不一致沒法徹底解決,引入快取之後,binlog同步時間間隔內,也無法避免讀舊資料。

但是,有沒有辦法做到,即使引入快取,不一致不會比“不引入快取”更糟呢?這是更為實際的優化目標。

思路轉化為:在從庫同步完成之後,如果有舊資料入快取,應該及時把這個舊資料淘汰掉。

四、不一致優化

如上圖所述,在併發讀寫導致快取中讀入了髒資料之後:

(6)主從同步

(7)通過工具訂閱從庫的binlog,這裡能夠最準確的知道,從庫資料同步完成的時間

畫外音:本圖畫的訂閱工具是DTS,可以是cannal,也可以自己訂閱和分析binlog

(8)從庫執行完寫操作,向快取再次發起刪除,淘汰這段時間內可能寫入快取的舊資料

如此這般,至少能夠保證,引入快取之後,主從不一致,不會比沒有引入快取更壞。

畫外音:即使引入快取,也只有一個很小的時間間隔,可能讀到舊資料。

五、結尾

問:如何完全避免,主從同步時間差,資料的一致性?

答:詳見《資料庫主從不一致,怎麼解?》。

問:該方案,只能優化,併發讀寫情況下,快取與資料庫一致性問題。如果,快取與資料庫兩次操作,原子性被破壞(例如:修改資料庫成功,淘汰快取失敗,導致的資料不一致),如何優化資料的一致性呢?

答:詳見《究竟先操作快取,還是資料庫?》。


【本文轉載自架構師之路微信公眾號,作者:58沈劍,原文連結:https://mp.weixin.qq.com/s/gYQvP69sao8U0azuNRMG1w】

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2157921/,如需轉載,請註明出處,否則將追究法律責任。

相關文章