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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

一道之前的面試題:

如何保證緩存和數據庫的一致性?


方案分析

更新緩存策略方式常見的有下面幾種:

  • 先更新緩存,再更新數據庫

  • 先更新數據庫,再更新緩存

  • 先刪除緩存,再更新數據庫

  • 先更新數據庫,再刪除緩存

  • 下面一一介紹!

    方案一:更新緩存,更新數據庫

    這種方式可輕易排除,因為如果先更新緩存成功,但是數據庫更新失敗,則肯定會造成數據不一致。

    方案二:更新數據庫,更新緩存

    這種緩存更新策略俗稱雙寫,存在問題是:并發更新數據庫場景下,會將臟數據刷到緩存

    updateDB(); updateRedis();

    舉例:如果在兩個操作之間數據庫和緩存又被后面請求修改,此時再去更新緩存已經是過期數據了。

    方案三:刪除緩存,更新數據庫

    存在問題:更新數據庫之前,若有查詢請求,會將臟數據刷到緩存

    deleteRedis(); updateDB();

    舉例:如果在兩個操作之間發生了數據查詢,那么會有舊數據放入緩存。

    該方案會導致請求數據不一致

    如果同時有一個請求A進行更新操作,另一個請求B進行查詢操作。那么會出現如下情形:

    • 請求A進行寫操作,刪除緩存

    • 請求B查詢發現緩存不存在

    • 請求B去數據庫查詢得到舊值

    • 請求B將舊值寫入緩存

    • 請求A將新值寫入數據庫

    上述情況就會導致不一致的情形出現。而且,如果不采用給緩存設置過期時間策略,該數據永遠都是臟數據。

    方案四:更新數據庫,刪除緩存

    存在問題:在更新數據庫之前有查詢請求,并且緩存失效了,會查詢數據庫,然后更新緩存。如果在查詢數據庫和更新緩存之間進行了數據庫更新的操作,那么就會把臟數據刷到緩存

    updateDB(); deleteRedis();

    舉例:如果在查詢數據庫和放入緩存這兩個操作中間發生了數據更新并且刪除緩存,那么會有舊數據放入緩存。

    假設有兩個請求,一個請求A做查詢操作,一個請求B做更新操作,那么會有如下情形產生

    • 緩存剛好失效

    • 請求A查詢數據庫,得一個舊值

    • 請求B將新值寫入數據庫

    • 請求B刪除緩存

    • 請求A將查到的舊值寫入緩存

    如果發生上述情況,確實是會發生臟數據。但是發生上述情況有一個先天性條件,就是寫數據庫操作比讀數據庫操作耗時更短

    不過數據庫的讀操作的速度遠快于寫操作的

    因此這一情形很難出現。

    ?

    方案對比

    方案1和方案2的共同缺點:

    并發更新數據庫場景下,會將臟數據刷到緩存,但一般并發寫的場景概率都相對小一些;

    線程安全角度,會產生臟數據,比如:

    • 線程A更新了數據庫

    • 線程B更新了數據庫

    • 線程B更新了緩存

    • 線程A更新了緩存

    方案3和方案4的共同缺點:

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

    • 主從延時問題:不管是先刪除還是后刪除,數據庫主從延時可能導致臟數據的產生。

    • 緩存刪除失敗:如果緩存刪除失敗,則都會產生臟數據。

    問題解決思路:延遲雙刪,添加重試機制,下面介紹!

    更新緩存還是刪除緩存?

    1.更新緩存緩存需要有一定的維護成本,而且會存在并發更新的問題

    2.寫多讀少的情況下,讀請求還沒有來,緩存以及被更新很多次,沒有起到緩存的作用

    3.放入緩存的值可能是經過復雜計算的,如果每次更新,都計算寫入緩存的值,浪費性能的

    刪除緩存優點:簡單、成本低,容易開發;缺點:會造成一次cache miss

    如果更新緩存開銷較小并且讀多寫少,基本不會有寫并發的時候可以才用更新緩存,否則通用做法還是刪除緩存。


    總結

    ?

    推薦方案

    延遲雙刪

    采用更新前后雙刪除緩存策略

    public?void?write(String?key,Object?data){redis.del(key);db.update(data);Thread.sleep(1000);redis.del(key);}
    • 先淘汰緩存

    • 再寫數據庫

    • 休眠1秒,再次淘汰緩存

    大家應該評估自己的項目的讀數據業務邏輯的耗時。然后寫數據的休眠時間則在讀數據業務邏輯的耗時基礎上即可。

    這么做的目的,就是確保讀請求結束,寫請求可以刪除讀請求造成的緩存臟數據。

    問題及解法:

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

    將第二次刪除作為異步的,提交一個延遲的執行任務

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

    添加重試機制,例如:將刪除失敗的key,寫入消息隊列;但對業務耦合有些嚴重;

    延時工具可以選擇:

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

    Jdk調度線程池,quartz定時任務,利用jdk自帶的delayQueue,netty的HashWheelTimer,Rabbitmq的延時隊列,等等

    ?

    實際場景

    我們有個商品中心的場景,是讀多寫少的服務,并且寫數據會發送MQ通知下游拿數據,這樣就需要嚴格保證緩存和數據庫的一致性,需要提供高可靠的系統服務能力。

    寫緩存策略

  • 緩存key設置失效時間

  • 先DB操作,再緩存失效

  • 寫操作都標記key(美團中間件)強制走主庫

  • 接入美團中間件監聽binlog(美團中間件)變化的數據在進行兜底,再刪除緩存

  • 讀緩存策略

  • 先判斷是否走主庫

  • 如果走主庫,則使用標記(美團中間件)查主庫

  • 如果不是,則查看緩存中是否有數據

  • 緩存中有數據,則使用緩存數據作為結果

  • 如果沒有,則查DB數據,再寫數據到緩存

  • ?

    注意

    關于緩存過期時間的問題

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

    但是如果沒有設置過期時間,那么不一致問題就只能等到下次更新數據時解決。

    所以一定要設置緩存過期時間。

    有道無術,術可成;有術無道,止于術

    歡迎大家關注Java之道公眾號

    好文章,我在看??

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。