最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中如何保證緩存一致性問(wèn)題

 更新時(shí)間:2022年04月21日 11:44:21   作者:程序員段飛?  
這篇文章主要介紹了Java中如何保證緩存一致性問(wèn)題,文章將通過(guò)主題提出的問(wèn)題展開(kāi)一些解決方案分析,需要的小伙伴可以參考一下

前言:

一道之前的面試題:

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

下面介紹幾種方案(大家回答的時(shí)候最好根據(jù)自己的業(yè)務(wù),結(jié)合下面的方案)

方案分析

更新緩存策略方式常見(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ù),更新緩存

這種緩存更新策略俗稱雙寫,存在問(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ù)之前,若有查詢請(qǐng)求,會(huì)將臟數(shù)據(jù)刷到緩存

deleteRedis();
updateDB();

舉例:如果在兩個(gè)操作之間發(fā)生了數(shù)據(jù)查詢,那么會(huì)有舊數(shù)據(jù)放入緩存。

該方案會(huì)導(dǎo)致請(qǐng)求數(shù)據(jù)不一致

如果同時(shí)有一個(gè)請(qǐng)求A進(jìn)行更新操作,另一個(gè)請(qǐng)求B進(jìn)行查詢操作。那么會(huì)出現(xiàn)如下情形:

  • 請(qǐng)求A進(jìn)行寫操作,刪除緩存
  • 請(qǐng)求B查詢發(fā)現(xiàn)緩存不存在
  • 請(qǐng)求B去數(shù)據(jù)庫(kù)查詢得到舊值
  • 請(qǐng)求B將舊值寫入緩存
  • 請(qǐng)求A將新值寫入數(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ù)之前有查詢請(qǐng)求,并且緩存失效了,會(huì)查詢數(shù)據(jù)庫(kù),然后更新緩存。如果在查詢數(shù)據(jù)庫(kù)和更新緩存之間進(jìn)行了數(shù)據(jù)庫(kù)更新的操作,那么就會(huì)把臟數(shù)據(jù)刷到緩存

updateDB();
deleteRedis();

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

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

  • 緩存剛好失效
  • 請(qǐng)求A查詢數(shù)據(jù)庫(kù),得一個(gè)舊值
  • 請(qǐng)求B將新值寫入數(shù)據(jù)庫(kù)
  • 請(qǐng)求B刪除緩存
  • 請(qǐng)求A將查到的舊值寫入緩存

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

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

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

方案對(duì)比

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

并發(fā)更新數(shù)據(jù)庫(kù)場(chǎng)景下,會(huì)將臟數(shù)據(jù)刷到緩存,但一般并發(fā)寫的場(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)生。
  • 緩存刪除失?。喝绻彺鎰h除失敗,則都會(huì)產(chǎn)生臟數(shù)據(jù)。

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

更新緩存還是刪除緩存?

  • 1.更新緩存緩存需要有一定的維護(hù)成本,而且會(huì)存在并發(fā)更新的問(wèn)題
  • 2.寫多讀少的情況下,讀請(qǐng)求還沒(méi)有來(lái),緩存以及被更新很多次,沒(méi)有起到緩存的作用
  • 3.放入緩存的值可能是經(jīng)過(guò)復(fù)雜計(jì)算的,如果每次更新,都計(jì)算寫入緩存的值,浪費(fèi)性能的

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

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

總結(jié)

方案問(wèn)題問(wèn)題出現(xiàn)概率推薦程度
更新緩存 -> 更新數(shù)據(jù)庫(kù)為了保證數(shù)據(jù)準(zhǔn)確性,數(shù)據(jù)必須以數(shù)據(jù)庫(kù)更新結(jié)果為準(zhǔn),所以該方案絕不可行不推薦
更新數(shù)據(jù)庫(kù) -> 更新緩存并發(fā)更新數(shù)據(jù)庫(kù)場(chǎng)景下,會(huì)將臟數(shù)據(jù)刷到緩存并發(fā)寫場(chǎng)景,概率一般寫請(qǐng)求較多時(shí)會(huì)出現(xiàn)不一致問(wèn)題,不推薦使用。
刪除緩存 -> 更新數(shù)據(jù)庫(kù)更新數(shù)據(jù)庫(kù)之前,若有查詢請(qǐng)求,會(huì)將臟數(shù)據(jù)刷到緩存并發(fā)讀場(chǎng)景,概率較大讀請(qǐng)求較多時(shí)會(huì)出現(xiàn)不一致問(wèn)題,不推薦使用
更新數(shù)據(jù)庫(kù) -> 刪除緩存在更新數(shù)據(jù)庫(kù)之前有查詢請(qǐng)求,并且緩存失效了,會(huì)查詢數(shù)據(jù)庫(kù),然后更新緩存。如果在查詢數(shù)據(jù)庫(kù)和更新緩存之間進(jìn)行了數(shù)據(jù)庫(kù)更新的操作,那么就會(huì)把臟數(shù)據(jù)刷到緩存并發(fā)讀場(chǎng)景&讀操作慢于寫操作,概率最小讀操作比寫操作更慢的情況較少,相比于其他方式出錯(cuò)的概率小一些。勉強(qiáng)推薦。

推薦方案

延遲雙刪

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

public void write(String key,Object data){
  redis.del(key);
     db.update(data);
     Thread.sleep(1000);
     redis.del(key);
 }
  • 先淘汰緩存
  • 再寫數(shù)據(jù)庫(kù)
  • 休眠1秒,再次淘汰緩存

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

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

問(wèn)題及解法:

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

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

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

添加重試機(jī)制,例如:將刪除失敗的key,寫入消息隊(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)景,是讀多寫少的服務(wù),并且寫數(shù)據(jù)會(huì)發(fā)送MQ通知下游拿數(shù)據(jù),這樣就需要嚴(yán)格保證緩存和數(shù)據(jù)庫(kù)的一致性,需要提供高可靠的系統(tǒng)服務(wù)能力。

寫緩存策略

  • 緩存key設(shè)置失效時(shí)間
  • 先DB操作,再緩存失效
  • 寫操作都標(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ù),再寫數(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í)間。

到此這篇關(guān)于Java緩存一致性問(wèn)題的文章就介紹到這了,更多相關(guān)Java緩存一致性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Springboot實(shí)現(xiàn)攔截器的兩種方式

    淺談Springboot實(shí)現(xiàn)攔截器的兩種方式

    本文詳細(xì)的介紹了Springboot攔截器的兩種方式實(shí)現(xiàn),一種就是用攔截器,一種就是過(guò)濾器,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • SpringBoot響應(yīng)出現(xiàn)中文亂碼的解決方法

    SpringBoot響應(yīng)出現(xiàn)中文亂碼的解決方法

    這篇文章主要介紹了SpringBoot響應(yīng)出現(xiàn)中文亂碼的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起來(lái)學(xué)習(xí)吧
    2024-02-02
  • SpringBoot2.6.x升級(jí)后循環(huán)依賴及Swagger無(wú)法使用問(wèn)題

    SpringBoot2.6.x升級(jí)后循環(huán)依賴及Swagger無(wú)法使用問(wèn)題

    這篇文章主要為大家介紹了SpringBoot2.6.x升級(jí)后循環(huán)依賴及Swagger無(wú)法使用問(wèn)題,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Java中的讀寫鎖ReentrantReadWriteLock源碼分析

    Java中的讀寫鎖ReentrantReadWriteLock源碼分析

    這篇文章主要介紹了Java中的讀寫鎖ReentrantReadWriteLock源碼分析,ReentrantReadWriteLock 分為讀鎖和寫鎖兩個(gè)實(shí)例,讀鎖是共享鎖,可被多個(gè)線程同時(shí)使用,寫鎖是獨(dú)占鎖,持有寫鎖的線程可以繼續(xù)獲取讀鎖,反之不行,需要的朋友可以參考下
    2023-12-12
  • java8中的Collectors.groupingBy用法詳解

    java8中的Collectors.groupingBy用法詳解

    這篇文章主要介紹了java8中的Collectors.groupingBy用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java中條件運(yùn)算符的嵌套使用技巧總結(jié)

    Java中條件運(yùn)算符的嵌套使用技巧總結(jié)

    在Java中,我們經(jīng)常需要使用條件運(yùn)算符來(lái)進(jìn)行多個(gè)條件的判斷和選擇,條件運(yùn)算符可以簡(jiǎn)化代碼,提高代碼的可讀性和執(zhí)行效率,本文將介紹條件運(yùn)算符的嵌套使用技巧,幫助讀者更好地掌握條件運(yùn)算符的應(yīng)用,需要的朋友可以參考下
    2023-11-11
  • mybatis實(shí)現(xiàn)表與對(duì)象的關(guān)聯(lián)關(guān)系_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    mybatis實(shí)現(xiàn)表與對(duì)象的關(guān)聯(lián)關(guān)系_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了mybatis實(shí)現(xiàn)表與對(duì)象的關(guān)聯(lián)關(guān)系_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,需要的朋友可以參考下
    2017-09-09
  • Java中的HttpServletRequestWrapper用法解析

    Java中的HttpServletRequestWrapper用法解析

    這篇文章主要介紹了Java中的HttpServletRequestWrapper用法解析,HttpServletRequest 對(duì)參數(shù)值的獲取實(shí)際調(diào)的是org.apache.catalina.connector.Request,沒(méi)有提供對(duì)應(yīng)的set方法修改屬性,所以不能對(duì)前端傳來(lái)的參數(shù)進(jìn)行修改,需要的朋友可以參考下
    2024-01-01
  • JUC中的wait與notify方法實(shí)現(xiàn)原理詳解

    JUC中的wait與notify方法實(shí)現(xiàn)原理詳解

    這篇文章主要介紹了JUC中的wait與notify方法實(shí)現(xiàn)原理,在進(jìn)行wait()之前,就代表著需要爭(zhēng)奪Synchorized,而Synchronized代碼塊通過(guò)javap生成的字節(jié)碼中包含monitor?enter和monitor?exit兩個(gè)指令
    2023-03-03
  • Java實(shí)現(xiàn)BASE64編碼和解碼的方法

    Java實(shí)現(xiàn)BASE64編碼和解碼的方法

    本篇文章主要介紹了Java實(shí)現(xiàn)BASE64編碼和解碼的方法,BASE64編碼通常用于轉(zhuǎn)換二進(jìn)制數(shù)據(jù)為文本數(shù)據(jù),有需要的可以了解一下。
    2016-11-11

最新評(píng)論

富锦市| 吉木乃县| 广东省| 新密市| 临潭县| 锡林郭勒盟| 高州市| 丰原市| 北安市| 赞皇县| 绥棱县| 阜宁县| 莲花县| 崇仁县| 新乡市| 枣庄市| 淮滨县| 普陀区| 北宁市| 泾源县| 汶川县| 长沙县| 青阳县| 晋江市| 农安县| 沙田区| 越西县| 朝阳县| 萨迦县| 长葛市| 阳曲县| 改则县| 南汇区| 天柱县| 襄樊市| 东台市| 新丰县| 抚顺市| 登封市| 广汉市| 榆树市|