為什么對緩存只刪除不更新不更新緩存是防止并發(fā)更新導(dǎo)致的數(shù)據(jù)不一致。所以為了降低數(shù)據(jù)不一致的概率,不應(yīng)該更新緩存,而是直接將其刪除,然后等待下次發(fā)生cache miss時再把數(shù)據(jù)庫中的數(shù)據(jù)同步到緩存。...
為什么對緩存只刪除不更新
不更新緩存是防止并發(fā)更新導(dǎo)致的數(shù)據(jù)不一致。
所以為了降低數(shù)據(jù)不一致的概率,不應(yīng)該更新緩存,而是直接將其刪除,
然后等待下次發(fā)生cache miss時再把數(shù)據(jù)庫中的數(shù)據(jù)同步到緩存。
先更新數(shù)據(jù)庫還是先刪除緩存?
有兩個選擇:
1. 先刪除緩存,再更新數(shù)據(jù)庫
2. 先更新數(shù)據(jù)庫,再刪除緩存
如果先刪除緩存,有一個明顯的邏輯錯誤:考慮兩個并發(fā)操作,線程A刪除緩存后,線程B讀該數(shù)據(jù)時會發(fā)生Cache Miss,然后從數(shù)據(jù)庫中讀出該數(shù)據(jù)并同步到緩存中,此時線程A更新了數(shù)據(jù)庫。
結(jié)果導(dǎo)致,緩存中是老數(shù)據(jù),數(shù)據(jù)庫中是新數(shù)據(jù),并且之后的讀操作都會直接讀取緩存中的臟數(shù)據(jù)。(直到key過期被刪除或者被LRU策略踢出)
如果數(shù)據(jù)庫更新成功后,再刪除緩存,就不會有上面這個問題。
可能是由于數(shù)據(jù)庫優(yōu)先,第二種方式也被稱為Cache Aside Pattern。
Cache Aside Pattern
cache aside在絕大多數(shù)情況下能做到數(shù)據(jù)一致性,但是在極端情況仍然存在問題。
首先更新數(shù)據(jù)庫(A)和刪除緩存(B)不是原子操作,任何在A之后B之前的讀操作,都會讀到redis中的舊數(shù)據(jù)。
但是,正常情況下操作緩存的速度會很快,通常是毫秒級,出現(xiàn)上述情況的概率很低。
更新完數(shù)據(jù)庫后,線程意外被kill掉,由于沒有刪除緩存,緩存中的臟數(shù)據(jù)會一直存在。
線程A讀數(shù)據(jù)時cache miss,從Mysql中查詢到數(shù)據(jù),還沒來得及同步到redis中,
此時線程B更新了數(shù)據(jù)庫并把Redis中的舊值刪除。隨后,線程A把之前查到的數(shù)據(jù)同步到了Redis。
顯然,此時redis中的是臟數(shù)據(jù)。
通常數(shù)據(jù)庫讀操作比寫操作快很多,所以除非線程A在同步redis前意外卡住了,否則發(fā)生上述情況的概率極低。
雖然以上情況都有可能發(fā)生,但是發(fā)生的概率相比“先刪除緩存再更新數(shù)據(jù)庫”會低很多。
Read/Write Through Pattern
cache aside是我們自己的應(yīng)用程序維護(hù)兩個數(shù)據(jù)存儲系統(tǒng),而Read/Write Through Pattern是把同步數(shù)據(jù)的問題交給緩存系統(tǒng)了,應(yīng)用程序不需要關(guān)心。
Read Through是指發(fā)生cache miss時,緩存系統(tǒng)自動去數(shù)據(jù)庫加載數(shù)據(jù)。
Write Through是指如果cache miss,直接更新數(shù)據(jù)庫,然后返回,如果cache hit,則更新緩存后,由緩存系統(tǒng)自動同步到數(shù)據(jù)庫。
以Redis為例,通常我們不會把數(shù)據(jù)庫的數(shù)據(jù)全部緩存到redis,而是采用一定的數(shù)據(jù)精簡或壓縮策略,以節(jié)省緩存空間。
就是說,讓緩存系統(tǒng)設(shè)計出通用的緩存方案不太現(xiàn)實,不過根據(jù)自己的業(yè)務(wù)定制一個在項目內(nèi)部通用的中間件是可行的。
Write Behind
Write Behind方案在更新數(shù)據(jù)時,只更新緩存,不更新數(shù)據(jù)庫。而是由另外一個服務(wù)異步的把數(shù)據(jù)更新到數(shù)據(jù)庫。
邏輯上,和Linux中的write back很類似。這個設(shè)計的好處是,I/O操作很快,因為是純內(nèi)存操作。
但是由于異步寫庫,可能要犧牲一些數(shù)據(jù)一致性,譬如突然宕機(jī)會丟失所有未寫入數(shù)據(jù)庫的內(nèi)存數(shù)據(jù)。
阿里巴巴的Canal中間件是一種相反的設(shè)計,它先更新mysql,然后通過binlog把數(shù)據(jù)自動同步到redis。
這種方案會全量同步數(shù)據(jù)到redis,不適合只緩存熱點數(shù)據(jù)的應(yīng)用。
總結(jié)
以上沒有哪種方案是完美的,都無法做到強(qiáng)一致性。
我們總要在性能和數(shù)據(jù)準(zhǔn)確性之間做出妥協(xié)。
來源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡(luò)平臺,并已注明來源、出處,如果轉(zhuǎn)載侵犯您的版權(quán)或非授權(quán)發(fā)布,請聯(lián)系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內(nèi)容的準(zhǔn)確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負(fù)責(zé),僅作分享之用,文章版權(quán)及插圖屬于原作者。
Copyright©2013-2025 ?JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢平臺保留所有權(quán)利
蘇公網(wǎng)安備32010402000125
蘇ICP備14051488號-3技術(shù)支持:南京博盛藍(lán)睿網(wǎng)絡(luò)科技有限公司
南京思必達(dá)教育科技有限公司版權(quán)所有 百度統(tǒng)計