美團(tuán)面試題:緩存一致性,我是這么回答的!
一道之前的面試題:
如何保證緩存和數(shù)據(jù)庫(kù)的一致性?
方案分析
更新緩存策略方式常見(jiàn)的有下面幾種:
先更新緩存,再更新數(shù)據(jù)庫(kù)
先更新數(shù)據(jù)庫(kù),再更新緩存
先刪除緩存,再更新數(shù)據(jù)庫(kù)
先更新數(shù)據(jù)庫(kù),再刪除緩存
下面一一介紹!
方案一:更新緩存,更新數(shù)據(jù)庫(kù)
這種方式可輕易排除,因?yàn)槿绻雀戮彺娉晒?,但是?shù)據(jù)庫(kù)更新失敗,則肯定會(huì)造成數(shù)據(jù)不一致。
方案二:更新數(shù)據(jù)庫(kù),更新緩存
這種緩存更新策略俗稱(chēng)雙寫(xiě),存在問(wèn)題是:并發(fā)更新數(shù)據(jù)庫(kù)場(chǎng)景下,會(huì)將臟數(shù)據(jù)刷到緩存
updateDB();
updateRedis();
舉例:如果在兩個(gè)操作之間數(shù)據(jù)庫(kù)和緩存又被后面請(qǐng)求修改,此時(shí)再去更新緩存已經(jīng)是過(guò)期數(shù)據(jù)了。

方案三:刪除緩存,更新數(shù)據(jù)庫(kù)
存在問(wèn)題:更新數(shù)據(jù)庫(kù)之前,若有查詢(xún)請(qǐng)求,會(huì)將臟數(shù)據(jù)刷到緩存
deleteRedis();
updateDB();
舉例:如果在兩個(gè)操作之間發(fā)生了數(shù)據(jù)查詢(xún),那么會(huì)有舊數(shù)據(jù)放入緩存。

該方案會(huì)導(dǎo)致請(qǐng)求數(shù)據(jù)不一致
如果同時(shí)有一個(gè)請(qǐng)求A進(jìn)行更新操作,另一個(gè)請(qǐng)求B進(jìn)行查詢(xún)操作。那么會(huì)出現(xiàn)如下情形:
請(qǐng)求A進(jìn)行寫(xiě)操作,刪除緩存 請(qǐng)求B查詢(xún)發(fā)現(xiàn)緩存不存在 請(qǐng)求B去數(shù)據(jù)庫(kù)查詢(xún)得到舊值 請(qǐng)求B將舊值寫(xiě)入緩存 請(qǐng)求A將新值寫(xiě)入數(shù)據(jù)庫(kù)
updateDB();
deleteRedis();

緩存剛好失效 請(qǐng)求A查詢(xún)數(shù)據(jù)庫(kù),得一個(gè)舊值 請(qǐng)求B將新值寫(xiě)入數(shù)據(jù)庫(kù) 請(qǐng)求B刪除緩存 請(qǐng)求A將查到的舊值寫(xiě)入緩存
方案對(duì)比
線(xiàn)程A更新了數(shù)據(jù)庫(kù) 線(xiàn)程B更新了數(shù)據(jù)庫(kù) 線(xiàn)程B更新了緩存 線(xiàn)程A更新了緩存
主從延時(shí)問(wèn)題:不管是先刪除還是后刪除,數(shù)據(jù)庫(kù)主從延時(shí)可能導(dǎo)致臟數(shù)據(jù)的產(chǎn)生。 緩存刪除失敗:如果緩存刪除失敗,則都會(huì)產(chǎn)生臟數(shù)據(jù)。
總結(jié)

推薦方案
延遲雙刪
public void write(String key,Object data){
redis.del(key);
db.update(data);
Thread.sleep(1000);
redis.del(key);
}
先淘汰緩存 再寫(xiě)數(shù)據(jù)庫(kù) 休眠1秒,再次淘汰緩存

Thread.currentThread().sleep(1000);實(shí)際場(chǎng)景
寫(xiě)緩存策略
緩存key設(shè)置失效時(shí)間 先DB操作,再緩存失效 寫(xiě)操作都標(biāo)記key(美團(tuán)中間件)強(qiáng)制走主庫(kù) 接入美團(tuán)中間件監(jiān)聽(tīng)binlog(美團(tuán)中間件)變化的數(shù)據(jù)在進(jìn)行兜底,再刪除緩存

讀緩存策略
先判斷是否走主庫(kù) 如果走主庫(kù),則使用標(biāo)記(美團(tuán)中間件)查主庫(kù) 如果不是,則查看緩存中是否有數(shù)據(jù) 緩存中有數(shù)據(jù),則使用緩存數(shù)據(jù)作為結(jié)果 如果沒(méi)有,則查DB數(shù)據(jù),再寫(xiě)數(shù)據(jù)到緩存

注意
有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
