溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

發(fā)布時(shí)間:2023-03-29 16:28:48 來(lái)源:億速云 閱讀:127 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

    1、四種同步策略:

    想要保證緩存與數(shù)據(jù)庫(kù)的雙寫一致,一共有4種方式,即4種同步策略:

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

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

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

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

    從這4種同步策略中,我們需要作出比較的是:

    更新緩存與刪除緩存哪種方式更合適?應(yīng)該先操作數(shù)據(jù)庫(kù)還是先操作緩存?

    2、更新緩存還是刪除緩存

    下面,我們來(lái)分析一下,應(yīng)該采用更新緩存還是刪除緩存的方式。

    2.1 更新緩存

    優(yōu)點(diǎn)每次數(shù)據(jù)變化都及時(shí)更新緩存,所以查詢時(shí)不容易出現(xiàn)未命中的情況。

    缺點(diǎn)更新緩存的消耗比較大。如果數(shù)據(jù)需要經(jīng)過(guò)復(fù)雜的計(jì)算再寫入緩存,那么頻繁的更新緩存,就會(huì)影響服務(wù)器的性能。如果是寫入數(shù)據(jù)頻繁的業(yè)務(wù)場(chǎng)景,那么可能頻繁的更新緩存時(shí),卻沒(méi)有業(yè)務(wù)讀取該數(shù)據(jù)。

    2.2 刪除緩存

    優(yōu)點(diǎn)操作簡(jiǎn)單,無(wú)論更新操作是否復(fù)雜,都是將緩存中的數(shù)據(jù)直接刪除。

    缺點(diǎn)刪除緩存后,下一次查詢緩存會(huì)出現(xiàn)未命中,這時(shí)需要重新讀取一次數(shù)據(jù)庫(kù)。從上面的比較來(lái)看,一般情況下,刪除緩存是更優(yōu)的方案。

    3、先操作數(shù)據(jù)庫(kù)還是緩存

    下面,我們?cè)賮?lái)分析一下,應(yīng)該先操作數(shù)據(jù)庫(kù)還是先操作緩存。
    首先,我們將先刪除緩存與先更新數(shù)據(jù)庫(kù),在出現(xiàn)失敗時(shí)進(jìn)行一個(gè)對(duì)比:

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

    保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

    如上圖,是先刪除緩存再更新數(shù)據(jù)庫(kù),在出現(xiàn)失敗時(shí)可能出現(xiàn)的問(wèn)題:

    • 線程A刪除緩存成功,線程A更新數(shù)據(jù)庫(kù)失??;

    • 線程B從緩存中讀取數(shù)據(jù);由于緩存被刪,進(jìn)程B無(wú)法從緩存中得到數(shù)據(jù),進(jìn)而從數(shù)據(jù)庫(kù)讀取數(shù)據(jù);此時(shí)數(shù)據(jù)庫(kù)中的數(shù)據(jù)更新失敗,線程B從數(shù)據(jù)庫(kù)成功獲取舊的數(shù)據(jù),然后將數(shù)據(jù)更新到了緩存。

    • 最終,緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)是一致的,但仍然是舊的數(shù)據(jù)

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

    保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

    如上圖,是先更新數(shù)據(jù)庫(kù)再刪除緩存,在出現(xiàn)失敗時(shí)可能出現(xiàn)的問(wèn)題:

    • 線程A更新數(shù)據(jù)庫(kù)成功,線程A刪除緩存失??;

    • 線程B讀取緩存成功,由于緩存刪除失敗,所以線程B讀取到的是緩存中舊的數(shù)據(jù)。

    • 最后線程A刪除緩存成功,有別的線程訪問(wèn)緩存同樣的數(shù)據(jù),與數(shù)據(jù)庫(kù)中的數(shù)據(jù)是一樣。

    • 最終,緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)是一致的,但是會(huì)有一些線程讀到舊的數(shù)據(jù)。

    經(jīng)過(guò)上面的比較,我們發(fā)現(xiàn)在出現(xiàn)失敗的時(shí)候,是無(wú)法明確分辨出先刪緩存和先更新數(shù)據(jù)庫(kù)哪個(gè)方式更好,以為它們都存在問(wèn)題。后面我們會(huì)進(jìn)一步對(duì)這兩種方式進(jìn)行比較,但是在這里我們先探討一下,上述場(chǎng)景出現(xiàn)的問(wèn)題,應(yīng)該如何解決呢?

    實(shí)際上,無(wú)論上面我們采用哪種方式去同步緩存與數(shù)據(jù)庫(kù),在第二步出現(xiàn)失敗的時(shí)候,都建議采用重試機(jī)制解決,上面兩幅圖中已經(jīng)畫了。

    下面我們?cè)賹⑾葎h緩存與先更新數(shù)據(jù)庫(kù),在沒(méi)有出現(xiàn)失敗時(shí)進(jìn)行對(duì)比:

    保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

    如上圖,是先刪除緩存再更新數(shù)據(jù)庫(kù),在沒(méi)有出現(xiàn)失敗時(shí)可能出現(xiàn)的問(wèn)題:

    • 線程A刪除緩存成功;

    • 線程B讀取緩存失??;

    • 線程B讀取數(shù)據(jù)庫(kù)成功,得到舊的數(shù)據(jù);

    • 線程B將舊的數(shù)據(jù)成功地更新到了緩存;

    • 線程A將新的數(shù)據(jù)成功地更新到數(shù)據(jù)庫(kù)。

    可見,進(jìn)程A的兩步操作均成功,但由于存在并發(fā),在這兩步之間,進(jìn)程B訪問(wèn)了緩存。最終結(jié)果是,緩存中存儲(chǔ)了舊的數(shù)據(jù),而數(shù)據(jù)庫(kù)中存儲(chǔ)了新的數(shù)據(jù),二者數(shù)據(jù)不一致。

    保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

    如上圖,是先更新數(shù)據(jù)庫(kù)再刪除緩存,在沒(méi)有出現(xiàn)失敗時(shí)可能出現(xiàn)的問(wèn)題:

    • 線程A更新數(shù)據(jù)庫(kù)成功;

    • 線程B讀取緩存成功;

    • 線程A刪除緩存成功。

    可見,最終緩存與數(shù)據(jù)庫(kù)的數(shù)據(jù)是一致的,并且都是最新的數(shù)據(jù)。但線程B在這個(gè)過(guò)程里讀到了舊的數(shù)據(jù),可能還有其他線程也像線程B一樣,在這兩步之間讀到了緩存中舊的數(shù)據(jù),但因?yàn)檫@兩步的執(zhí)行速度會(huì)比較快,所以影響不大。對(duì)于這兩步之后,其他進(jìn)程再讀取緩存數(shù)據(jù)的時(shí)候,就不會(huì)出現(xiàn)類似于進(jìn)程B的問(wèn)題了。

    最終結(jié)論:

    經(jīng)過(guò)對(duì)比你會(huì)發(fā)現(xiàn),先更新數(shù)據(jù)庫(kù)、再刪除緩存是影響更小的方案。如果第二步出現(xiàn)失敗的情況,則可以采用重試機(jī)制解決問(wèn)題。

    4、延時(shí)雙刪

    上面我們提到,如果是先刪緩存、再更新數(shù)據(jù)庫(kù),在沒(méi)有出現(xiàn)失敗時(shí)可能會(huì)導(dǎo)致數(shù)據(jù)的不一致。如果在實(shí)際的應(yīng)用中,出于某些考慮我們需要選擇這種方式,那有辦法解決這個(gè)問(wèn)題嗎?答案是有的,那就是采用延時(shí)雙刪的策略,延時(shí)雙刪的基本思路如下

    1. 刪除緩存;

    2. 更新數(shù)據(jù)庫(kù);

    3. sleep N毫秒;

    4. 再次刪除緩存。

    	public void write(String key, Object data) {
            Redis.delKey(key);
            db.updateData(data);
            Thread.sleep(1000);
            Redis.delKey(key);
        }

    阻塞一段時(shí)間之后,再次刪除緩存,就可以把這個(gè)過(guò)程中緩存中不一致的數(shù)據(jù)刪除掉。而具體的時(shí)間,要評(píng)估你這項(xiàng)業(yè)務(wù)的大致時(shí)間,按照這個(gè)時(shí)間來(lái)設(shè)定即可。

    4.1 采用讀寫分離的架構(gòu)怎么辦?

    如果數(shù)據(jù)庫(kù)采用的是讀寫分離的架構(gòu),那么又會(huì)出現(xiàn)新的問(wèn)題,如下圖:

    保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

    此時(shí)來(lái)了兩個(gè)請(qǐng)求,請(qǐng)求 A(更新操作) 和請(qǐng)求 B(查詢操作)

    1. 請(qǐng)求 A 更新操作,刪除了 Redis;

    2. 請(qǐng)求主庫(kù)進(jìn)?更新操作,主庫(kù)與從庫(kù)進(jìn)行同步數(shù)據(jù)的操作;

    3. 請(qǐng) B 查詢操作,發(fā)現(xiàn) Redis 中沒(méi)有數(shù)據(jù);

    4. 去從庫(kù)中拿去數(shù)據(jù);

    5. 此時(shí)同步數(shù)據(jù)還未完成,拿到的數(shù)據(jù)是舊數(shù)據(jù);

    此時(shí)的解決辦法就是如果是對(duì) Redis 進(jìn)行填充數(shù)據(jù)的查詢數(shù)據(jù)庫(kù)操作,那么就強(qiáng)制將其指向主庫(kù)進(jìn)?查詢。

    刪除失敗了怎么辦?

    如果刪除依然失敗,則可以增加重試的次數(shù),但是這個(gè)次數(shù)要有限制,當(dāng)超出一定的次數(shù)時(shí),要采取報(bào)錯(cuò)、記日志、發(fā)郵件提醒等措施。

    5、利用消息隊(duì)列進(jìn)行刪除的補(bǔ)償

    先更新數(shù)據(jù)庫(kù),后刪除緩存這?種情況也會(huì)出現(xiàn)問(wèn)題,比如更新數(shù)據(jù)庫(kù)成功了,但是在刪除緩存的階段出錯(cuò)了沒(méi)有刪除成功,那么此時(shí)再讀取緩存的時(shí)候每次都是錯(cuò)誤的數(shù)據(jù)了。

    保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

    此時(shí)解決方案就是利用消息隊(duì)列進(jìn)行刪除的補(bǔ)償。具體的業(yè)務(wù)邏輯?語(yǔ)?描述如下:

    1. 請(qǐng)求 線程A 先對(duì)數(shù)據(jù)庫(kù)進(jìn)行更新操作;

    2. 在對(duì) Redis 進(jìn)行刪除操作的時(shí)候發(fā)現(xiàn)報(bào)錯(cuò),刪除失??;

    3. 此時(shí)將Redis 的 key 作為消息體發(fā)送到消息隊(duì)列中;

    4. 系統(tǒng)接收到消息隊(duì)列發(fā)送的消息后再次對(duì) Redis 進(jìn)行刪除操作;

    但是這個(gè)方案會(huì)有?個(gè)缺點(diǎn)就是會(huì)對(duì)業(yè)務(wù)代碼造成大量的侵入,深深的耦合在?起,所以這時(shí)會(huì)有?個(gè)優(yōu)化的方法,我們知道對(duì) Mysql 數(shù)據(jù)庫(kù)更新操作后再 binlog 日志中我們都能夠找到相應(yīng)的操作,那么我們可以訂閱 Mysql 數(shù)據(jù)庫(kù)的 binlog 日志對(duì)緩存進(jìn)行操作。

    保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么

    讀到這里,這篇“保證Redis緩存與數(shù)據(jù)庫(kù)一致性的方法是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI