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

Redis與MySQL數(shù)據(jù)一致性問題的策略模式及解決方案

 更新時間:2024年07月29日 09:49:49   作者:echola_mendes  
開發(fā)中,一般會使用Redis緩存一些常用的熱點(diǎn)數(shù)據(jù)用來減少數(shù)據(jù)庫IO,提高系統(tǒng)的吞吐量,本文將給大家介紹了Redis與MySQL數(shù)據(jù)一致性問題的策略模式及解決方案,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下

在開發(fā)中,一般會使用Redis緩存一些常用的熱點(diǎn)數(shù)據(jù)用來減少數(shù)據(jù)庫IO,提高系統(tǒng)的吞吐量

先了解一下分布式系統(tǒng)中的一致性概念。

強(qiáng)一致性:所有節(jié)點(diǎn)的數(shù)據(jù)必須實(shí)時同步,保證任何時候讀取到的數(shù)據(jù)都是最新的。

弱一致性:系統(tǒng)允許數(shù)據(jù)暫時不一致,但最終會達(dá)到一致狀態(tài)。

最終一致性:數(shù)據(jù)更新后,經(jīng)過一段時間,系統(tǒng)會逐步達(dá)到一致狀態(tài)。這個時間不固定,但在業(yè)務(wù)允許的范圍內(nèi)。

雙寫一致性:當(dāng)數(shù)據(jù)同時存在于緩存(Redis)和數(shù)據(jù)庫(MySQL)時,兩者之間數(shù)據(jù)一致

 那么容易出現(xiàn)數(shù)據(jù)一致性問題的場景是:

  • 數(shù)據(jù)寫入數(shù)據(jù)庫,未更新緩存
  • 刪除緩存后,數(shù)據(jù)庫更新失敗

一、策略模式

緩存可以提升性能、緩解數(shù)據(jù)庫壓力,但是使用緩存也會導(dǎo)致數(shù)據(jù)不一致性的問題。有三種經(jīng)典的緩存使用模式:

  • Cache-Aside Pattern
  • Read-Through/Write-through
  • Write-behind

1、旁路緩存模式(Cache Aside Pattern)

Cache Aside Pattern的提出是為了盡可能地解決緩存與數(shù)據(jù)庫的數(shù)據(jù)不一致問題

流程:

  • 讀取操作:先從緩存中讀取數(shù)據(jù),緩存命中返回結(jié)果;緩存未命中,從DB中讀取數(shù)據(jù),并將數(shù)據(jù)寫入緩存。
  • 更新操作:先更DB,再刪除緩存中的舊數(shù)據(jù)。

在日常開發(fā)中,一般使用了Cache Aside Pattern緩存更新策略模式,以數(shù)據(jù)庫為主,緩存為輔

public class CacheAsidePattern {
 
    private RedisService redis;
    private DatabaseService database;
 
    // 讀取操作
    public String getData(String key) {
        // 從緩存中獲取數(shù)據(jù)
        String value = redis.get(key);
        if (value == null) {
            // 緩存未命中,從數(shù)據(jù)庫獲取數(shù)據(jù)
            value = database.get(key);
            if (value != null) {
                // 將數(shù)據(jù)寫入緩存
                redis.set(key, value);
            }
        }
        return value;
    }
 
    // 更新操作
    public void updateData(String key, String value) {
        // 更新數(shù)據(jù)庫
        database.update(key, value);
        // 刪除緩存中的舊數(shù)據(jù)
        redis.delete(key);
    }
}

?:Cache-Aside在操作數(shù)據(jù)庫時,為什么是先操作數(shù)據(jù)庫呢?為什么不先操作緩存呢?

1、先刪除緩存后,數(shù)據(jù)庫更新失敗

線程1:刪除緩存A,由于網(wǎng)絡(luò)問題沒有操作數(shù)據(jù)庫失敗

線程2:查詢A,緩存無數(shù)據(jù),并把A寫入緩存

線程1:網(wǎng)絡(luò)堵塞結(jié)束,修改數(shù)據(jù)庫A為B

那么此時緩存是A【舊數(shù)據(jù)】,數(shù)據(jù)庫是B【新數(shù)據(jù)】,臟數(shù)據(jù)出現(xiàn)啦?。。?/p>

因此,Cache-Aside緩存模式,選擇了先操作數(shù)據(jù)庫而不是先操作緩存

2、先操作數(shù)據(jù)庫再刪除緩存方案

線程1:操作數(shù)據(jù)庫,A更新數(shù)據(jù)為B,刪除緩存A

線程2:查詢A,緩存無數(shù)據(jù),并把B寫入緩存

這種方案下,在數(shù)據(jù)庫更新成功后到刪除Redis緩存數(shù)據(jù)之前的這段時間中,其他線程讀取的數(shù)據(jù)都是舊數(shù)據(jù),等Redis刪除緩存后會重新從數(shù)據(jù)庫中讀取最新數(shù)據(jù)同步到Redis,這樣可以在一定程度上保證數(shù)據(jù)的最終一致性

但是在極端情況下,線程1的緩存刪除失敗,線程2讀取的也就是舊數(shù)據(jù)A,而不是新數(shù)據(jù)B了

這種方案也就是旁路緩存模式,那么Cache-Aside的優(yōu)缺點(diǎn)就是:

優(yōu)點(diǎn)

簡單易懂,易于實(shí)現(xiàn)

讀性能高,因?yàn)榇蟛糠肿x操作都會命中緩存

缺點(diǎn)

更新數(shù)據(jù)庫后緩存可能還沒刪除,存在短暫的不一致

刪除緩存后,如果數(shù)據(jù)庫更新失敗,會導(dǎo)致數(shù)據(jù)不一致

:Cache-Aside在寫入請求的時候,為什么是刪除緩存而不是更新緩存呢?

線程1:操作數(shù)據(jù)庫,更新數(shù)據(jù)為A,由于網(wǎng)絡(luò)問題未更新緩存

線程2:操作數(shù)據(jù)庫,更新數(shù)據(jù)為B,更新緩存為B

線程1:網(wǎng)絡(luò)堵塞結(jié)束,更新緩存為A

那么此時緩存是A【舊數(shù)據(jù)】,數(shù)據(jù)庫是B【新數(shù)據(jù)】,臟數(shù)據(jù)出現(xiàn)啦?。。?/p>

如果是刪除緩存取代更新緩存則不會出現(xiàn)這個臟數(shù)據(jù)問題?。?!

因此,Cache-Aside緩存模式,選擇了刪除緩存而不是更新緩存

適應(yīng)場景:適用于讀多寫少的場景,特別是對數(shù)據(jù)一致性要求不是特別高的應(yīng)用

2、讀寫穿透(Read-Through/Write-Through)

Read-Through:當(dāng)緩存未命中時,自動從數(shù)據(jù)庫加載數(shù)據(jù),并寫入緩存

Write-Through:當(dāng)緩存更新時,同步將數(shù)據(jù)寫入數(shù)據(jù)庫

和旁路緩存模式很像,只有寫操作不太一樣

public class ReadWriteThroughPattern {
 
    private RedisService redis;
    private DatabaseService database;
 
    // Read-Through
    public String readThrough(String key) {
        // 從緩存中獲取數(shù)據(jù)
        String value = redis.get(key);
        if (value == null) {
            // 緩存未命中,從數(shù)據(jù)庫獲取數(shù)據(jù)
            value = database.get(key);
            if (value != null) {
                // 將數(shù)據(jù)寫入緩存
                redis.set(key, value);
            }
        }
        return value;
    }
 
    // Write-Through
    public void writeThrough(String key, String value) {
        // 將數(shù)據(jù)寫入緩存
        redis.set(key, value);
        // 同步將數(shù)據(jù)寫入數(shù)據(jù)庫
        database.update(key, value);
    }
}

優(yōu)點(diǎn)

  • 保證了數(shù)據(jù)的強(qiáng)一致性,緩存和數(shù)據(jù)庫的數(shù)據(jù)始終同步。
  • 讀寫操作都由緩存處理,數(shù)據(jù)庫壓力較小。

缺點(diǎn)

  • 寫操作的延遲較高,因?yàn)?strong>每次寫入緩存時都需要同步寫入數(shù)據(jù)庫,增加了系統(tǒng)的響應(yīng)時間
  • 實(shí)現(xiàn)復(fù)雜度較高,需要額外的緩存同步機(jī)制

適應(yīng)場景:適合讀多寫多、且對數(shù)據(jù)一致性要求較高的場景

3、異步緩存寫入(Write Behind)

異步緩存就是緩存更新后,異步批量寫入數(shù)據(jù)庫。這種策略適用于可以容忍一定數(shù)據(jù)不一致的高性能場景

示例代碼:

public class WriteBehindPattern {
 
    private RedisService redis;
    private DatabaseService database;
    private UpdateQueue updateQueue;
 
    // 異步緩存寫入
    public void writeBehind(String key, String value) {
        // 將數(shù)據(jù)寫入緩存
        redis.set(key, value);
        // 異步將數(shù)據(jù)寫入數(shù)據(jù)庫
        asyncDatabaseUpdate(key, value);
    }
 
    private void asyncDatabaseUpdate(String key, String value) {
        // 異步操作,將更新請求放入隊(duì)列
        updateQueue.add(new UpdateTask(key, value));
    }
}

優(yōu)點(diǎn)

寫操作的性能非常高,因?yàn)橹恍韪戮彺妫瑪?shù)據(jù)庫更新是異步進(jìn)行的

適用于對寫操作性能要求較高的場景

缺點(diǎn)

存在數(shù)據(jù)不一致的風(fēng)險(xiǎn),緩存更新后數(shù)據(jù)庫可能還未更新。

實(shí)現(xiàn)復(fù)雜度較高,需要處理異步操作中的異常和重試

適應(yīng)場景:大批量數(shù)據(jù)讀取,允許短期數(shù)據(jù)不一致,寫密集型場景

二、一致性解決方案

緩存系統(tǒng)適用的場景就是非強(qiáng)一致性的場景,它屬于CAP中的AP

CAP理論,指的是在一個分布式系統(tǒng)中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區(qū)容錯性),三者不可得兼。

沒辦法做到數(shù)據(jù)庫與緩存絕對的一致性,但通過一些方案優(yōu)化處理,是可以保證弱一致性,最終一致性

1、緩存延遲雙刪

流程:

  • 先刪除緩存
  • 再更新數(shù)據(jù)庫
  • 休眠一會(比如1秒),再次刪除緩存

但休眠的時間內(nèi),可能有臟數(shù)據(jù),且第二次刪除也可能失敗,導(dǎo)致的數(shù)據(jù)不一致問題

延遲雙刪策略只能保證最終的一致性,不能保證強(qiáng)一致性。由于對Redis的操作和Mysql的操作不是原子性操作,所以如果想保證數(shù)據(jù)的強(qiáng)一致性就需要加鎖控制,如下圖所示

加鎖之后勢必會帶來系統(tǒng)的吞吐量的下降,所以需要衡量利弊來確定是否使用加鎖

方案優(yōu)化:刪除失敗就多刪除幾次呀,保證刪除緩存成功就可以了!

所以可以引入刪除緩存重試機(jī)制

2、刪除重試機(jī)制

刪除緩存失敗,則將這些key放入到消息隊(duì)列中,消費(fèi)消息隊(duì)列的消息,獲取要刪除的key,重試刪除緩存操作

3、讀取biglog異步刪除緩存

重試刪除緩存機(jī)制還可以吧,就是會造成好多業(yè)務(wù)代碼入侵

方案優(yōu)化:通過數(shù)據(jù)庫的binlog來異步淘汰key

以MySQL為例,通過canal監(jiān)聽binlog日志感知數(shù)據(jù)的變動后,canal客戶端執(zhí)行刪除Redis緩存數(shù)據(jù),如果緩存數(shù)據(jù)刪除失敗那么發(fā)送一條MQ消息讓canal客戶端繼續(xù)執(zhí)行刪除操作,這樣可以保證數(shù)據(jù)的最終一致性,但是這樣也增加了系統(tǒng)的復(fù)雜性

三、總結(jié)

(1)實(shí)際開發(fā)中一般使用使用了Cache Aside Pattern緩存更新策略模式,此方案最大程度上保證了數(shù)據(jù)的一致性并且實(shí)現(xiàn)也最簡單

(2)無論是先操作數(shù)據(jù)庫再刪除緩存還是先刪除緩存再操作數(shù)據(jù)庫都有可能會出現(xiàn)刪除緩存失敗的情況,所以需要加入刪除重試機(jī)制

(3)如果想要Redis和Mysql的數(shù)據(jù)強(qiáng)一致性,可以考慮使用加鎖的方式實(shí)現(xiàn)

以上就是Redis與MySQL數(shù)據(jù)一致性問題的策略模式及解決方案的詳細(xì)內(nèi)容,更多關(guān)于Redis與MySQL數(shù)據(jù)一致性的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Redis與數(shù)據(jù)庫數(shù)據(jù)一致性的原因及解決方案

    Redis與數(shù)據(jù)庫數(shù)據(jù)一致性的原因及解決方案

    Redis作為一種高效的鍵值對存儲系統(tǒng),常用于緩存數(shù)據(jù)庫減少IO操作,下面這篇文章主要介紹了Redis與數(shù)據(jù)庫數(shù)據(jù)一致性的原因及解決方案,文中介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04
  • Redis安裝啟動及常見數(shù)據(jù)類型

    Redis安裝啟動及常見數(shù)據(jù)類型

    這篇文章主要介紹了Redis安裝啟動及常見數(shù)據(jù)類型,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 利用Redis的有序集合實(shí)現(xiàn)排行榜功能實(shí)例代碼

    利用Redis的有序集合實(shí)現(xiàn)排行榜功能實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于如何利用Redis的有序集合實(shí)現(xiàn)排行榜功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Redis鎖的過期時間小于業(yè)務(wù)的執(zhí)行時間如何續(xù)期

    Redis鎖的過期時間小于業(yè)務(wù)的執(zhí)行時間如何續(xù)期

    本文主要介紹了Redis鎖的過期時間小于業(yè)務(wù)的執(zhí)行時間如何續(xù)期,Redisson它能給Redis分布式鎖實(shí)現(xiàn)過期時間自動續(xù)期,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-05-05
  • redis主從切換導(dǎo)致的數(shù)據(jù)丟失與陷入只讀狀態(tài)故障解決方案

    redis主從切換導(dǎo)致的數(shù)據(jù)丟失與陷入只讀狀態(tài)故障解決方案

    這篇文章主要介紹了redis主從切換導(dǎo)致的數(shù)據(jù)丟失與陷入只讀狀態(tài)故障解決方案的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • 利用Redis實(shí)現(xiàn)訂單30分鐘自動取消

    利用Redis實(shí)現(xiàn)訂單30分鐘自動取消

    本文主要介紹了利用Redis實(shí)現(xiàn)訂單30分鐘自動取消,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 深入淺析Redis 集群伸縮原理

    深入淺析Redis 集群伸縮原理

    Redis 集群提供了靈活的節(jié)點(diǎn)擴(kuò)容和收縮方案。在不影響集群對外服務(wù)的情況下,可以為集群添加節(jié)點(diǎn)進(jìn)行擴(kuò)容,也可以下線部分節(jié)點(diǎn)進(jìn)行縮容,接下來通過本文給大家分享Redis 集群伸縮原理,感興趣的朋友一起看看吧
    2021-05-05
  • redis-copy使用6379端口無法連接到Redis服務(wù)器的問題

    redis-copy使用6379端口無法連接到Redis服務(wù)器的問題

    這篇文章主要介紹了redis-copy使用6379端口無法連接到Redis服務(wù)器的問題的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • 淺談Redis變慢的原因及排查方法

    淺談Redis變慢的原因及排查方法

    本文主要介紹了淺談Redis變慢的原因及排查方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Redis兩種持久化方案RDB和AOF詳解

    Redis兩種持久化方案RDB和AOF詳解

    這篇文章主要介紹了Redis 兩種持久化方案,RDB(Redis DataBase)和 AOF(Append Only File),給大家提供參考,一起學(xué)習(xí)下。
    2017-11-11

最新評論

垣曲县| 株洲市| 锡林郭勒盟| 南岸区| 克拉玛依市| 水城县| 稻城县| 邵武市| 西贡区| 古蔺县| 犍为县| 汝城县| 资溪县| 昌平区| 明水县| 英山县| 镇宁| 霞浦县| 邯郸县| 湾仔区| 同江市| 同心县| 夏邑县| 同心县| 永修县| 鄂尔多斯市| 高淳县| 莱芜市| 寻乌县| 宾阳县| 长沙县| 大埔县| 襄城县| 房产| 崇信县| 蓝田县| 乐都县| 浪卡子县| 平罗县| 辰溪县| 富裕县|