數據庫與緩存不一致,你會怎么辦?
今天聊聊數據庫yu緩存的一致性問題。
數據庫主從,為什么會不一致?
先回顧下,無緩存時,數據庫主從不一致問題。
如上圖,發生的場景是,寫后立刻讀:
- 主庫一個寫請求(主從沒同步完成);
- 從庫接著一個讀請求,讀到了舊數據;
- 最后,主從同步完成;
導致的結果是:主動同步完成之前,會讀取到舊數據。
可以看到,主從不一致的影響時間很短,在主從同步完成后,就會讀到新數據。
緩存與數據庫,什么時候會不一致?
再看,引入緩存后,緩存和數據庫不一致問題。
如上圖,發生的場景也是,寫后立刻讀:
- (1+2)先一個寫請求,淘汰緩存,寫數據庫;
- (3+4+5)接著立刻一個讀請求,讀緩存,cache miss,讀從庫,寫緩存放入數據,以便后續的讀能夠cache hit(主從同步沒有完成,緩存中放入了舊數據);
- (6)最后,主從同步完成;
導致的結果是:舊數據放入緩存,即使主從同步完成,后續仍然會從緩存一直讀取到舊數據。
可以看到,加入緩存后,導致的不一致影響時間會很長,并且最終也不會達到一致。
為什么會出現這類不一致?
如上所述,緩存與數據庫數據不一致,根本上是由數據庫主從不一致引起的。當主庫上發生寫操作之后,從庫binlog同步的時間間隔內,讀請求,可能導致有舊數據入緩存。
假如主從不一致沒法徹底解決,引入緩存之后,binlog同步時間間隔內,也無法避免讀舊數據。
但是,有沒有辦法做到,即使引入緩存,不一致不會比“不引入緩存”更糟呢?
這是更為實際的優化目標。
思路轉化為:在從庫同步完成之后,如果有舊數據入緩存,應該及時把這個舊數據淘汰掉。
緩存與數據庫不一致,可以怎么優化?
如上圖所述,在并發讀寫導致緩存中讀入了臟數據之后:
- (6)主從同步;
- (7)通過工具訂閱從庫的binlog,這里能夠最準確的知道,從庫數據同步完成的時間;
- (8)從庫執行完寫操作,向緩存再次發起刪除,淘汰這段時間內可能寫入緩存的舊數據;
如此這般,至少能夠保證,引入緩存之后,主從不一致,不會比沒有引入緩存更壞。
知其然,知其所以然。
思路比結論更重要。