日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

美团面试题:缓存一致性,我是这么回答的!

發(fā)布時(shí)間:2025/3/16 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 美团面试题:缓存一致性,我是这么回答的! 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一道之前的面試題:

如何保證緩存和數(shù)據(jù)庫(kù)的一致性?


方案分析

更新緩存策略方式常見(jiàn)的有下面幾種:

  • 先更新緩存,再更新數(shù)據(jù)庫(kù)

  • 先更新數(shù)據(jù)庫(kù),再更新緩存

  • 先刪除緩存,再更新數(shù)據(jù)庫(kù)

  • 先更新數(shù)據(jù)庫(kù),再刪除緩存

  • 下面一一介紹!

    方案一:更新緩存,更新數(shù)據(jù)庫(kù)

    這種方式可輕易排除,因?yàn)槿绻雀戮彺娉晒?#xff0c;但是數(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ù)

    上述情況就會(huì)導(dǎo)致不一致的情形出現(xiàn)。而且,如果不采用給緩存設(shè)置過(guò)期時(shí)間策略,該數(shù)據(jù)永遠(yuǎn)都是臟數(shù)據(jù)。

    方案四:更新數(shù)據(jù)庫(kù),刪除緩存

    存在問(wèn)題:在更新數(shù)據(jù)庫(kù)之前有查詢(xún)請(qǐng)求,并且緩存失效了,會(huì)查詢(xún)數(shù)據(jù)庫(kù),然后更新緩存。如果在查詢(xún)數(shù)據(jù)庫(kù)和更新緩存之間進(jìn)行了數(shù)據(jù)庫(kù)更新的操作,那么就會(huì)把臟數(shù)據(jù)刷到緩存

    updateDB(); deleteRedis();

    舉例:如果在查詢(xún)數(shù)據(jù)庫(kù)和放入緩存這兩個(gè)操作中間發(fā)生了數(shù)據(jù)更新并且刪除緩存,那么會(huì)有舊數(shù)據(jù)放入緩存。

    假設(shè)有兩個(gè)請(qǐng)求,一個(gè)請(qǐng)求A做查詢(xún)操作,一個(gè)請(qǐng)求B做更新操作,那么會(huì)有如下情形產(chǎn)生

    • 緩存剛好失效

    • 請(qǐng)求A查詢(xún)數(shù)據(jù)庫(kù),得一個(gè)舊值

    • 請(qǐng)求B將新值寫(xiě)入數(shù)據(jù)庫(kù)

    • 請(qǐng)求B刪除緩存

    • 請(qǐng)求A將查到的舊值寫(xiě)入緩存

    如果發(fā)生上述情況,確實(shí)是會(huì)發(fā)生臟數(shù)據(jù)。但是發(fā)生上述情況有一個(gè)先天性條件,就是寫(xiě)數(shù)據(jù)庫(kù)操作比讀數(shù)據(jù)庫(kù)操作耗時(shí)更短

    不過(guò)數(shù)據(jù)庫(kù)的讀操作的速度遠(yuǎn)快于寫(xiě)操作的

    因此這一情形很難出現(xiàn)。

    ?

    方案對(duì)比

    方案1和方案2的共同缺點(diǎn):

    并發(fā)更新數(shù)據(jù)庫(kù)場(chǎng)景下,會(huì)將臟數(shù)據(jù)刷到緩存,但一般并發(fā)寫(xiě)的場(chǎng)景概率都相對(duì)小一些;

    線程安全角度,會(huì)產(chǎn)生臟數(shù)據(jù),比如:

    • 線程A更新了數(shù)據(jù)庫(kù)

    • 線程B更新了數(shù)據(jù)庫(kù)

    • 線程B更新了緩存

    • 線程A更新了緩存

    方案3和方案4的共同缺點(diǎn):

    不管采用哪種順序,2種方式都是存在一些問(wèn)題的:

    • 主從延時(shí)問(wèn)題:不管是先刪除還是后刪除,數(shù)據(jù)庫(kù)主從延時(shí)可能導(dǎo)致臟數(shù)據(jù)的產(chǎn)生。

    • 緩存刪除失敗:如果緩存刪除失敗,則都會(huì)產(chǎn)生臟數(shù)據(jù)。

    問(wèn)題解決思路:延遲雙刪,添加重試機(jī)制,下面介紹!

    更新緩存還是刪除緩存?

    1.更新緩存緩存需要有一定的維護(hù)成本,而且會(huì)存在并發(fā)更新的問(wèn)題

    2.寫(xiě)多讀少的情況下,讀請(qǐng)求還沒(méi)有來(lái),緩存以及被更新很多次,沒(méi)有起到緩存的作用

    3.放入緩存的值可能是經(jīng)過(guò)復(fù)雜計(jì)算的,如果每次更新,都計(jì)算寫(xiě)入緩存的值,浪費(fèi)性能的

    刪除緩存優(yōu)點(diǎn):簡(jiǎn)單、成本低,容易開(kāi)發(fā);缺點(diǎn):會(huì)造成一次cache miss

    如果更新緩存開(kāi)銷(xiāo)較小并且讀多寫(xiě)少,基本不會(huì)有寫(xiě)并發(fā)的時(shí)候可以才用更新緩存,否則通用做法還是刪除緩存。


    總結(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秒,再次淘汰緩存

    大家應(yīng)該評(píng)估自己的項(xiàng)目的讀數(shù)據(jù)業(yè)務(wù)邏輯的耗時(shí)。然后寫(xiě)數(shù)據(jù)的休眠時(shí)間則在讀數(shù)據(jù)業(yè)務(wù)邏輯的耗時(shí)基礎(chǔ)上即可。

    這么做的目的,就是確保讀請(qǐng)求結(jié)束,寫(xiě)請(qǐng)求可以刪除讀請(qǐng)求造成的緩存臟數(shù)據(jù)。

    問(wèn)題及解法:

    1、同步刪除,吞吐量降低如何處理

    將第二次刪除作為異步的,提交一個(gè)延遲的執(zhí)行任務(wù)

    2、解決刪除失敗的方式:

    添加重試機(jī)制,例如:將刪除失敗的key,寫(xiě)入消息隊(duì)列;但對(duì)業(yè)務(wù)耦合有些嚴(yán)重;

    延時(shí)工具可以選擇:

    最普通的阻塞Thread.currentThread().sleep(1000);

    Jdk調(diào)度線程池,quartz定時(shí)任務(wù),利用jdk自帶的delayQueue,netty的HashWheelTimer,Rabbitmq的延時(shí)隊(duì)列,等等

    ?

    實(shí)際場(chǎng)景

    我們有個(gè)商品中心的場(chǎng)景,是讀多寫(xiě)少的服務(wù),并且寫(xiě)數(shù)據(jù)會(huì)發(fā)送MQ通知下游拿數(shù)據(jù),這樣就需要嚴(yán)格保證緩存和數(shù)據(jù)庫(kù)的一致性,需要提供高可靠的系統(tǒng)服務(wù)能力。

    寫(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ù)到緩存

  • ?

    注意

    關(guān)于緩存過(guò)期時(shí)間的問(wèn)題

    如果緩存設(shè)置了過(guò)期時(shí)間,那么上述的所有不一致情況都只是暫時(shí)的。

    但是如果沒(méi)有設(shè)置過(guò)期時(shí)間,那么不一致問(wèn)題就只能等到下次更新數(shù)據(jù)時(shí)解決。

    所以一定要設(shè)置緩存過(guò)期時(shí)間

    有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)

    歡迎大家關(guān)注Java之道公眾號(hào)

    好文章,我在看??

    總結(jié)

    以上是生活随笔為你收集整理的美团面试题:缓存一致性,我是这么回答的!的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。