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