欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis中緩存和數(shù)據(jù)庫(kù)雙寫(xiě)數(shù)據(jù)不一致的原因及解決方案

 更新時(shí)間:2024年03月14日 09:44:18   作者:coffee_babe  
這篇文章主要介紹了Redis中緩存和數(shù)據(jù)庫(kù)雙寫(xiě)數(shù)據(jù)不一致的原因及解決方案,文中通過(guò)圖文結(jié)合的方式講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

先更新數(shù)據(jù)庫(kù),還是先更新緩存?

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

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

在這里插入圖片描述

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

舉個(gè)例子,比如【請(qǐng)求A】和【請(qǐng)求B】?jī)蓚€(gè)請(qǐng)求,同時(shí)更新【同一條】數(shù)據(jù),則可能出現(xiàn)圖中的順序:

【請(qǐng)求A】先將數(shù)據(jù)庫(kù)的數(shù)據(jù)更新為1,然后在更新緩存前,【請(qǐng)求B】將數(shù)據(jù)庫(kù)的數(shù)據(jù)更新為2,緊接著把緩存更新為2,然后【請(qǐng)求A】更新緩存為1.此時(shí),數(shù)據(jù)庫(kù)中的數(shù)據(jù)是2,而緩存中的數(shù)據(jù)卻是1,出現(xiàn)了緩存和數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致的現(xiàn)象

在這里插入圖片描述

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

舉個(gè)例子,【請(qǐng)求A】和【請(qǐng)求B】?jī)蓚€(gè)請(qǐng)求,同時(shí)更新【同一條】數(shù)據(jù),則可能出現(xiàn)這樣的順序:

【請(qǐng)求A】先將緩存的數(shù)據(jù)更新為1,然后在更新數(shù)據(jù)庫(kù)前,【請(qǐng)求B】來(lái)了,將緩存的數(shù)據(jù)更新為2,緊接著把把數(shù)據(jù)庫(kù)更新為2,然后【請(qǐng)求A】將數(shù)據(jù)庫(kù)的數(shù)據(jù)更新為1.此時(shí),數(shù)據(jù)庫(kù)中的數(shù)據(jù)是1,而緩存中的數(shù)據(jù)卻是2,出現(xiàn)了緩存和數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致的現(xiàn)象

在這里插入圖片描述

結(jié)論

所以,無(wú)論是【先更新數(shù)據(jù)庫(kù),再更新緩存】,還是【先更新緩存,再更新數(shù)據(jù)庫(kù)】,這兩個(gè)方案都存在并發(fā)問(wèn)題,當(dāng)兩個(gè)請(qǐng)求并發(fā)更新同一條數(shù)據(jù)的時(shí)候,可能會(huì)出現(xiàn)緩存和數(shù)據(jù)庫(kù)中的數(shù)據(jù)不一致的現(xiàn)象

Cache Aside策略

Cache Aside(旁路緩存)策略,該策略可以細(xì)分為【讀策略】和【寫(xiě)策略】
寫(xiě)策略的步驟:

1.更新數(shù)據(jù)庫(kù)中的數(shù)據(jù);

2.刪除緩存中的數(shù)據(jù)

讀策略的步驟:

1.如果讀取的數(shù)據(jù)命中了緩存,則直接返回?cái)?shù)據(jù)

2.如果讀取的數(shù)據(jù)沒(méi)有命中緩存,則從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù),然后將數(shù)據(jù)寫(xiě)入到緩存,并且返回給用戶(hù)

但是【寫(xiě)策略】中的數(shù)據(jù)庫(kù)和緩存操作又有不同的順序:

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

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

在這里插入圖片描述

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

舉個(gè)例子,以用戶(hù)表的場(chǎng)景來(lái)分析。

假設(shè)某個(gè)用戶(hù)的年齡是20,請(qǐng)求A要更新用戶(hù)年齡為21,所以它會(huì)刪除緩存中的內(nèi)容。這時(shí),另一個(gè)請(qǐng)求B要讀取這個(gè)用戶(hù)的年齡,它查詢(xún)緩存發(fā)現(xiàn)未命中后,會(huì)從數(shù)據(jù)庫(kù)中讀取到年齡為20,并且寫(xiě)入到緩存中,然后請(qǐng)求A繼續(xù)更改數(shù)據(jù)庫(kù),將用戶(hù)的年齡更新為21.

最終,該用戶(hù)年齡在緩存中是20(舊值),在數(shù)據(jù)庫(kù)中是21(新值),緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)不一致??梢钥吹剑葎h除緩存,再更新數(shù)據(jù)庫(kù),在【讀+寫(xiě)】并發(fā)的時(shí)候,還是會(huì)出現(xiàn)緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)不一致的問(wèn)題

在這里插入圖片描述

解決方案:

針對(duì)【先刪除緩存,再更新數(shù)據(jù)庫(kù)】方法在【讀+寫(xiě)】并發(fā)請(qǐng)求而造成緩存不一致的解決辦法是【延遲雙刪】:
偽代碼示例。加了個(gè)睡眠時(shí)間,主要是為了確保請(qǐng)求A在睡眠的時(shí)候,請(qǐng)求B能夠在這一段時(shí)間內(nèi)完成【從數(shù)據(jù)庫(kù)讀取數(shù)據(jù),再把缺失的緩存寫(xiě)入緩存】的操作,然后請(qǐng)求A睡眠完,再刪除緩存。所以請(qǐng)求A的睡眠時(shí)間就需要大于請(qǐng)求B【從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)+寫(xiě)入緩存】的時(shí)間。但是具體睡眠多久其實(shí)我們是沒(méi)法準(zhǔn)確預(yù)估的,需要進(jìn)行統(tǒng)計(jì),所以這個(gè)方案盡可能保證一致性而已,極端情況下,依然也會(huì)出現(xiàn)緩存不一致的現(xiàn)象,因此,還是比較建議用【先更新數(shù)據(jù)庫(kù),再刪除緩存】的方案

#刪除緩存
redis.delKey(X);
#更新數(shù)據(jù)庫(kù)
db.update(X);
#睡眠
Thread.sleep(N);
#再刪除緩存
redis.delKey(X);

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

繼續(xù)用【讀+寫(xiě)】請(qǐng)求的并發(fā)的場(chǎng)景來(lái)分析。

假如某個(gè)用戶(hù)數(shù)據(jù)在緩存中不存在,請(qǐng)求A讀取讀取數(shù)據(jù)時(shí)從數(shù)據(jù)庫(kù)中查詢(xún)到年齡為20,在未寫(xiě)入緩存中時(shí)另一個(gè)請(qǐng)求B更新數(shù)據(jù)。它更新數(shù)據(jù)庫(kù)中的年齡為21,并且清空緩存。這時(shí)請(qǐng)求A把數(shù)據(jù)庫(kù)中讀到的年齡為20的數(shù)據(jù)寫(xiě)入到緩存中。最終,該用戶(hù)年齡在緩存中是20,數(shù)據(jù)庫(kù)中是21,緩存和數(shù)據(jù)庫(kù)數(shù)據(jù)不一致。

在這里插入圖片描述

分析

從上面的理論上分析,先更新數(shù)據(jù)庫(kù),再刪除緩存也是會(huì)出現(xiàn)數(shù)據(jù)不一致性的問(wèn)題,但是在實(shí)際中,這個(gè)問(wèn)題出現(xiàn)的概率并不高。因?yàn)榫彺娴膶?xiě)入通常要遠(yuǎn)遠(yuǎn)快于數(shù)據(jù)庫(kù)的寫(xiě)入,所以在實(shí)際中很難出現(xiàn)請(qǐng)求B已經(jīng)更新了數(shù)據(jù)庫(kù)并且刪除了緩存,請(qǐng)求A才更新完緩存的情況。而一旦請(qǐng)求A早于請(qǐng)求B刪除緩存之前更新了緩存,那么接下來(lái)的請(qǐng)求就會(huì)因?yàn)榫彺娌幻卸鴱臄?shù)據(jù)庫(kù)中重新讀取數(shù)據(jù),所以不會(huì)出現(xiàn)這種不一致的情況。所以,【先更新數(shù)據(jù)庫(kù)+再刪除緩存】的方案,是可以保證數(shù)據(jù)一致性的,再加上一個(gè)【過(guò)期時(shí)間】,就算在這期間存在緩存數(shù)據(jù)不一直,有過(guò)期時(shí)間來(lái)兜底,這樣也能達(dá)到最終一致。

【先更新數(shù)據(jù)庫(kù),再刪除緩存】存在的問(wèn)題:

前面的分析都是建立再這兩個(gè)操作都能同時(shí)執(zhí)行成功的情況下,如果在刪除緩存(第二個(gè)操作)的時(shí)候失敗了,導(dǎo)致緩存中的數(shù)據(jù)是舊值,如果沒(méi)有前面的過(guò)期時(shí)間兜底的話,后續(xù)的請(qǐng)求就會(huì)一直是緩存中的就數(shù)據(jù)

【先更新數(shù)據(jù)庫(kù),再刪除緩存】的方案雖然保證了數(shù)據(jù)庫(kù)與緩存的數(shù)據(jù)一致性,但是每次更新數(shù)據(jù)的時(shí)候,緩存的數(shù)據(jù)都會(huì)被刪除,這樣會(huì)對(duì)緩存的命中率帶來(lái)影響。所以,如果業(yè)務(wù)對(duì)緩存命中率有很高的要求,可以采用【更新數(shù)據(jù)庫(kù)+更新緩存】的方案,因?yàn)楦戮彺娌⒉粫?huì)出現(xiàn)緩存未命中的情況,但是這個(gè)方案,前面提到,在兩個(gè)更新請(qǐng)求并發(fā)執(zhí)行的時(shí)候,會(huì)出現(xiàn)數(shù)據(jù)不一致的問(wèn)題,因?yàn)楦聰?shù)據(jù)庫(kù)和更新緩存這兩個(gè)操作是獨(dú)立的,我們又沒(méi)有對(duì)操作做任何并發(fā)控制,那么當(dāng)兩個(gè)線程并發(fā)更新它們的話,就會(huì)因?yàn)閷?xiě)入順序的不同造成數(shù)據(jù)不一致需要增加一些手段來(lái)解決這個(gè)問(wèn)題,有兩種做法

  • 1.在更新緩存前先加個(gè)分布式鎖,保證同一時(shí)間之運(yùn)行一個(gè)請(qǐng)求更新緩存,就不會(huì)產(chǎn)生并發(fā)問(wèn)題了,但是引入鎖之后,對(duì)于寫(xiě)入性能就會(huì)帶來(lái)影響
  • 2.在更新完緩存時(shí),給緩存加上較短的過(guò)期時(shí)間,這樣即時(shí)出現(xiàn)緩存不一致的情況,緩存的數(shù)據(jù)也會(huì)很快過(guò)期,對(duì)業(yè)務(wù)來(lái)說(shuō)也可以接受

如何保證【先更新數(shù)據(jù)庫(kù),再刪除緩存】這兩個(gè)操作能執(zhí)行成功?

舉個(gè)例子:

應(yīng)用要把數(shù)據(jù)X的值從1更新為2,先成功更新了數(shù)據(jù)庫(kù),然后在Redis緩存中刪除X的緩存,但是這個(gè)操作卻失敗了,這個(gè)時(shí)候數(shù)據(jù)庫(kù)中的X的新值為2,Redis中的X的緩存值為1,出現(xiàn)了數(shù)據(jù)庫(kù)和緩存數(shù)據(jù)不一致的問(wèn)題。那么后續(xù)有訪問(wèn)數(shù)據(jù)X的請(qǐng)求,會(huì)先在Redis中查詢(xún),因?yàn)榫彺嬷胁](méi)有刪除,所以緩存命中,但是讀到的卻是舊值1.其實(shí)不管先操作數(shù)據(jù)庫(kù),還是先操作緩存,只要第二個(gè)操作失敗都會(huì)出現(xiàn)數(shù)據(jù)不一致的問(wèn)題,解決方案有兩種:

  • 1.重試機(jī)制
  • 2.訂閱MySQL binlog,再操作緩存

在這里插入圖片描述

1.重試機(jī)制。

我們可以引入消息隊(duì)列,將第二個(gè)操作(刪除緩存)要操作的數(shù)據(jù)加入到消息隊(duì)列,由消費(fèi)者來(lái)操作數(shù)據(jù)。

  • 1.1 如果應(yīng)用刪除緩存失敗,可以從消息隊(duì)列中重新讀取數(shù)據(jù),然后再次刪除緩存,這個(gè)就是重試機(jī)制。當(dāng)然,如果重試超過(guò)一定的次數(shù),還是沒(méi)有成功,就需要向業(yè)務(wù)層發(fā)送報(bào)錯(cuò)消息了
  • 1.2 如果刪除緩存成功,就要把數(shù)據(jù)從消息隊(duì)列中移除,避免重復(fù)操作,否則就繼續(xù)重試

在這里插入圖片描述

2.訂閱MySQL binlog,再操作緩存

【先更新數(shù)據(jù)庫(kù),再刪除緩存】的策略第一步是更新數(shù)據(jù)庫(kù),那么更新數(shù)據(jù)庫(kù)成功,就會(huì)產(chǎn)生一條變更日志,記錄在binlog里。于是我們就可以通過(guò)訂閱binlog日志,拿到具體要操作的數(shù)據(jù),然后再執(zhí)行緩存刪除,阿里開(kāi)源的Cannal中間件就是基于這個(gè)實(shí)現(xiàn)的。

Cannal模擬MySQL主從復(fù)制的交互協(xié)議,把自己偽裝成一個(gè)MySQL的從節(jié)點(diǎn),向MySQL主節(jié)點(diǎn)發(fā)送dump請(qǐng)求,MySQL收到請(qǐng)求后,就會(huì)開(kāi)始推送binlog給Cannal,Cannal解析binlog字節(jié)流之后,轉(zhuǎn)換為便于讀取的結(jié)構(gòu)化數(shù)據(jù),供下游程序訂閱使用.

在這里插入圖片描述

所以如果要想保證【先更新數(shù)據(jù)庫(kù),再刪除緩存】策略第二個(gè)操作能執(zhí)行成功,我們可以使用【消息隊(duì)列來(lái)重試緩存的刪除】,或者【訂閱MySQL binlog再操作緩存】,這兩種方法有一個(gè)共同的特點(diǎn),都是采用異步操作緩存

疑問(wèn)

為什么是刪除緩存,而不是更新緩存?

刪除一個(gè)數(shù)據(jù),相比更新一個(gè)數(shù)據(jù)更加輕量級(jí),出問(wèn)題的概率更小。在實(shí)際業(yè)務(wù)中,緩存的數(shù)據(jù)可能不是直接來(lái)自數(shù)據(jù)庫(kù)表,也許來(lái)自多張底層數(shù)據(jù)表的聚合。比如商品詳情信息,在底層可能會(huì)關(guān)聯(lián)商品表、價(jià)格表、庫(kù)存表等,如果更新了一個(gè)價(jià)格字段,那么就要更新整個(gè)數(shù)據(jù)庫(kù),還要關(guān)聯(lián)的去查詢(xún)和匯總各個(gè)周邊業(yè)務(wù)系統(tǒng)的數(shù)據(jù),這個(gè)操作會(huì)非常耗時(shí)。從另外一個(gè)角度,不是所有的緩存數(shù)據(jù)都是頻繁訪問(wèn)的,更新后的緩存可能會(huì)長(zhǎng)事件不被訪問(wèn),所以說(shuō),從計(jì)算資源和整體性能的考慮,更新的時(shí)候刪除緩存,等到下次查詢(xún)命中再填充緩存,是一個(gè)更好的方案。

系統(tǒng)設(shè)計(jì)中有一個(gè)設(shè)計(jì)叫Lazy Loading,適用于那些加載代價(jià)大的操作,刪除緩存而不是更新緩存,就是懶加載思想的一個(gè)應(yīng)用

以上就是Redis中緩存和數(shù)據(jù)庫(kù)雙寫(xiě)數(shù)據(jù)不一致的原因及解決方案的詳細(xì)內(nèi)容,更多關(guān)于Redis緩存和數(shù)據(jù)庫(kù)雙寫(xiě)不一致的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • redis學(xué)習(xí)之RDB、AOF與復(fù)制時(shí)對(duì)過(guò)期鍵的處理教程

    redis學(xué)習(xí)之RDB、AOF與復(fù)制時(shí)對(duì)過(guò)期鍵的處理教程

    這篇文章主要給大家介紹了關(guān)于redis學(xué)習(xí)之RDB、AOF與復(fù)制時(shí)對(duì)過(guò)期鍵處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • springmvc集成使用redis過(guò)程

    springmvc集成使用redis過(guò)程

    這篇文章主要介紹了springmvc集成使用redis過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Redis序列化存儲(chǔ)及日期格式的問(wèn)題處理

    Redis序列化存儲(chǔ)及日期格式的問(wèn)題處理

    這篇文章主要介紹了Redis序列化存儲(chǔ)及其日期格式的問(wèn)題處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 基于Redis+Lua腳本實(shí)現(xiàn)分布式限流組件封裝的方法

    基于Redis+Lua腳本實(shí)現(xiàn)分布式限流組件封裝的方法

    這篇文章主要介紹了基于Redis+Lua腳本實(shí)現(xiàn)分布式限流組件封裝,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Redis中List類(lèi)型的常用命令

    Redis中List類(lèi)型的常用命令

    本文主要介紹了Redis中List類(lèi)型的常用命令,包含12種常用命令,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • Redis讀寫(xiě)分離搭建的完整步驟

    Redis讀寫(xiě)分離搭建的完整步驟

    為滿足讀多寫(xiě)少的業(yè)務(wù)場(chǎng)景.最大化節(jié)約用戶(hù)成本.云數(shù)據(jù)庫(kù)Redis版推出了讀寫(xiě)分離規(guī)格,為用戶(hù)提供透明、高可用、高性能、高靈活的讀寫(xiě)分離服務(wù),這篇文章主要給大家介紹了關(guān)于Redis讀寫(xiě)分離搭建的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • Redis key命令key的儲(chǔ)存方式

    Redis key命令key的儲(chǔ)存方式

    這篇文章主要介紹了Redis key命令key的儲(chǔ)存方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Redis字符串原理的深入理解

    Redis字符串原理的深入理解

    這篇文章主要給大家介紹了關(guān)于Redis字符串原理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 詳解Redis如何多規(guī)則限流和防重復(fù)提交

    詳解Redis如何多規(guī)則限流和防重復(fù)提交

    市面上很多介紹redis如何實(shí)現(xiàn)限流的,但是大部分都有一個(gè)缺點(diǎn),就是只能實(shí)現(xiàn)單一的限流,但是如果想一個(gè)接口兩種規(guī)則都需要滿足呢,使用本文就來(lái)介紹一下redis實(shí)現(xiàn)分布式多規(guī)則限流的方式吧
    2023-12-12
  • Redis緩存更新策略詳解

    Redis緩存更新策略詳解

    這篇文章主要為大家詳細(xì)介紹了Redis緩存更新策略,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07

最新評(píng)論