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

Redis數(shù)據(jù)一致性問題的三種解決方案

 更新時間:2023年07月31日 09:26:57   作者:斷春風  
Redis(Remote?Dictionary?Server?),是一個高性能的基于Key-Value結(jié)構(gòu)存儲的NoSQL開源數(shù)據(jù)庫,大部分公司采用Redis來實現(xiàn)分布式緩存,用來提高數(shù)據(jù)查詢效率,本文就給大家介紹三種Redis數(shù)據(jù)一致性問題的解決方案,需要的朋友可以參考下

1、首先redis是什么

Redis(Remote Dictionary Server ),是一個高性能的基于Key-Value結(jié)構(gòu)存儲的NoSQL開源數(shù)據(jù)庫。大部分公司采用Redis來實現(xiàn)分布式緩存,用來提高數(shù)據(jù)查詢效率。

2、為什么會選Redis

在Web應用發(fā)展的初期,系統(tǒng)的訪問和并發(fā)并不高,交互也比較少。但隨著業(yè)務的擴大,訪問量的提升,使得服務器負載和關系型數(shù)據(jù)庫出現(xiàn)瓶頸,而導致瓶頸的源頭,主要體現(xiàn)在磁盤IO上。隨著互聯(lián)網(wǎng)的進一步發(fā)展,對系統(tǒng)性能有了更高的要求,Redis的出現(xiàn),解決了很多問題。至于我們?yōu)槭裁匆x擇Redis,我總結(jié)為以下六個原因:

1)、基于內(nèi)存存儲,可以降低對關系型數(shù)據(jù)庫的訪問頻次,從而緩解數(shù)據(jù)庫壓力

2)、數(shù)據(jù)IO操作能支持更高級別的QPS,官方發(fā)布的指標是10W;

3)、提供了比較多的數(shù)據(jù)存儲結(jié)構(gòu),比如string、list、hash、set、zset等等。

4)、采用單線程實現(xiàn)IO操作,避免了并發(fā)情況下的線程安全問題。

5)、可以支持數(shù)據(jù)持久化,避免因服務器故障導致數(shù)據(jù)丟失的問題

6)、Redis還提供了更多高級功能,比如分布式鎖、分布式隊列、排行榜、查找附近的人等功能,為更復雜的需求提供了成熟的解決方案。

3、 應用場景

緩存,作為Key-Value形態(tài)的內(nèi)存數(shù)據(jù)庫,Redis 最先會被想到的應用場景便是作為數(shù)據(jù)緩存

分布式鎖,分布式環(huán)境下對資源加鎖

分布式共享數(shù)據(jù),在多個應用之間共享

排行榜,自帶排序的數(shù)據(jù)結(jié)構(gòu)(zset)

消息隊列,pub/sub功能也可以用作發(fā)布者 / 訂閱者模型的消息

4、redis用作緩存時

4.1、作為緩存使用流程

緩存由于其高并發(fā)和高性能的特性,已經(jīng)在項目中被廣泛使用。在讀取緩存方面,大家沒啥疑問,都是按照下圖的流程來進行業(yè)務操作。

4.2、數(shù)據(jù)性一致性問題

例如我們使用Redis來作為緩存時,讓請求先訪問到Redis,而不是直接訪問數(shù)據(jù)庫。而在這種業(yè)務場景下,可能會出現(xiàn)緩存和數(shù)據(jù)庫數(shù)據(jù)不一致性的問題。

在更新的時候,操作緩存和數(shù)據(jù)庫無疑就是以下四種可能之一:

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

4.2.1、先更新緩存,再更新數(shù)據(jù)庫

如果我成功更新了緩存,但是在執(zhí)行更新數(shù)據(jù)庫的那一步,服務器突然宕機了,那么此時,我的緩存中是最新的數(shù)據(jù),而數(shù)據(jù)庫中是舊的數(shù)據(jù)。

臟數(shù)據(jù)就因此誕生了,并且如果我緩存的信息(是單獨某張表的),而且這張表也在其他表的關聯(lián)查詢中,那么其他表關聯(lián)查詢出來的數(shù)據(jù)也是臟數(shù)據(jù),結(jié)果就是直接會產(chǎn)生一系列的問題。

4.2.2、先更新數(shù)據(jù)庫,在更新緩存

只有等到緩存過期之后,才能訪問到正確的信息。那么在緩存沒過期的時間段內(nèi),所看到的都是臟數(shù)據(jù)。

以上兩圖中只要執(zhí)行第二步時失敗了,就必然會產(chǎn)生臟數(shù)據(jù)。

4.2.3、先刪除緩存,在更新數(shù)據(jù)庫

這種方式在沒有高并發(fā)的情況下,是可能保持數(shù)據(jù)一致性的。

如果只有第一步執(zhí)行成功,而第二步失敗,那么只有緩存中的數(shù)據(jù)被刪除了,但是數(shù)據(jù)庫沒有更新,那么在下一次進行查詢的時候,查不到緩存,只能重新查詢數(shù)據(jù)庫,構(gòu)建緩存,這樣其實也是相對做到了數(shù)據(jù)一致性。

但如果是處于讀寫并發(fā)的情況下,還是會出現(xiàn)數(shù)據(jù)不一致的情況:

執(zhí)行完成后,明顯可以看出,1號用戶所構(gòu)建的緩存,并不是最新的數(shù)據(jù),還是存在問題的

4.2.4、先更新數(shù)據(jù)庫,在刪除緩存

如果更新數(shù)據(jù)庫成功了,而刪除緩存失敗了,那么數(shù)據(jù)庫中就會是新數(shù)據(jù),而緩存中是舊數(shù)據(jù),數(shù)據(jù)就出現(xiàn)了不一致情況。

和之前一樣,如果兩段代碼都執(zhí)行成功,在并發(fā)情況下會是什么樣呢

還是會造成數(shù)據(jù)的不一致性。

但是此處達成這個數(shù)據(jù)不一致性的條件明顯會比起其他的方式更為困難

  • 時刻1:讀請求的時候,緩存正好過期
  • 時刻2:讀請求在寫請求更新數(shù)據(jù)庫之前查詢數(shù)據(jù)庫,
  • 時刻3:寫請求,在更新數(shù)據(jù)庫之后,要在讀請求成功寫入緩存前,先執(zhí)行刪除緩存操作。

這通常是很難做到的,因為在真正的并發(fā)開發(fā)中,更新數(shù)據(jù)庫是需要加鎖的,不然沒一點安全性~

一定程度上來講,這種方式還是解決了一定程度上的數(shù)據(jù)不一致性問題的。

4.3、總結(jié)

以上四種方式無論選擇那種方式,如果實在多服務或時并發(fā)的情況下,其實都是有可能產(chǎn)生數(shù)據(jù)不一致性的。

為了解決這個存在的問題有以下方式:

4.3.1、延遲雙刪

先進行緩存清除,再執(zhí)行update,最后(延遲N秒)再執(zhí)行緩存清除。進行兩次刪除,且中間需要延遲一段時間

public void write(String key,Object data){
// 延遲雙刪偽代碼
		deleteRedisCache(key);   // 刪除redis緩存
		updateMysqlSql(obj);        // 更新mysql
		Thread.sleep(100);           // 延遲一段時間
		deleteRedisCache(key);   // 再次刪除該key的緩存
}

延遲雙刪的流程圖:

解決這樣的問題,其實最好的方式就是在執(zhí)行完更新數(shù)據(jù)庫的操作后,先休眠一會兒,再進行一次緩存的刪除,以確保數(shù)據(jù)一致性

首先延遲刪除的時間需要大于 1號用戶執(zhí)行流程的總時間

就是1號用戶從數(shù)據(jù)庫讀取數(shù)據(jù) 寫入緩存時間

4.3.2、通過發(fā)送MQ,在消費者線程去同步Redis

無論是更新緩存還是刪除緩存,在同時操作緩存和數(shù)據(jù)庫時,都無法保證兩者都能一次性操作成功,所以我們最好的辦法就是重試,這個重試并不是立即重試,因為緩存和數(shù)據(jù)庫可能因為網(wǎng)絡或者其它原因停止服務了,立即重試成功率極低,而且重試會占用線程資源,顯然不合理,所以我們需要采用異步重試機制。

異步重試我們可以使用消息隊列來完成,因為消息隊列可以保證消息的可靠性,消息不會丟失,也可以保證正確消費,當且僅當消息消費成功后才會將消息從消息隊列中刪除。

優(yōu)點1:可以大幅減少接口的延遲返回的問題

優(yōu)點2:MQ本身有重試機制,無需人工去寫重試代碼

優(yōu)點3:解耦,把查詢Mysql和同步Redis完全分離,互不干擾

4.3.3、Canal 訂閱日志實現(xiàn)

當我們業(yè)務修改數(shù)據(jù)時,我們只需要更新數(shù)據(jù)庫,無需修改緩存,那什么時候修改緩存呢?

以mysql為例,在數(shù)據(jù)庫一條記錄發(fā)生變更時就會生成一條binlog日志,我們可以訂閱這種消息,拿到具體的數(shù)據(jù),然后根據(jù)日志消息更新緩存,訂閱日志目前比較流行的就是阿里開源的canal,那么我們的架構(gòu)就變?yōu)槿缦滦问健?/p>

訂閱數(shù)據(jù)庫變更日志,當數(shù)據(jù)庫發(fā)生變更時,我們可以拿到具體操作的數(shù)據(jù),然后再去根據(jù)具體的數(shù)據(jù),去刪除對應的緩存。

當然Canal 也是要配合消息隊列一起來使用的,因為其Canal本身是沒有數(shù)據(jù)處理能力的。

這個方式算的上徹底解耦了,應用程序代碼無需再管消息隊列方面發(fā)送失敗問題,全交由 Canal來發(fā)送。

以上就是Redis數(shù)據(jù)一致性問題的三種解決方案的詳細內(nèi)容,更多關于Redis數(shù)據(jù)一致性解決的資料請關注腳本之家其它相關文章!

相關文章

  • redis如何實現(xiàn)保存對象

    redis如何實現(xiàn)保存對象

    這篇文章主要介紹了redis如何實現(xiàn)保存對象,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Redis源碼設計剖析之事件處理示例詳解

    Redis源碼設計剖析之事件處理示例詳解

    這篇文章主要為大家介紹了Redis源碼設計剖析之事件處理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • redis 8.2.1 的密碼修改使用密文的操作方案

    redis 8.2.1 的密碼修改使用密文的操作方案

    本文介紹了Redis 8.2.1版本如何通過腳本解密后注入或使用外部認證模塊來實現(xiàn)密碼的安全存儲與使用,避免了配置文件中明文密碼的暴露風險,下面詳細說明具體情況和解決方案,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • Redis key命令key的儲存方式

    Redis key命令key的儲存方式

    這篇文章主要介紹了Redis key命令key的儲存方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 詳解redis中的下載和安裝(最新推薦)

    詳解redis中的下載和安裝(最新推薦)

    本文詳細介紹了如何在Linux和Docker上安裝、配置、啟動和關閉Redis,包括下載安裝包、解壓、編譯安裝、配置文件修改、前臺和后臺啟動、關閉以及Docker容器化部署等步驟,感興趣的朋友一起看看吧
    2025-03-03
  • Redis的持久化詳解

    Redis的持久化詳解

    Redis是一個基于內(nèi)存的數(shù)據(jù)庫,它的數(shù)據(jù)是存放在內(nèi)存中,內(nèi)存有個問題就是關閉服務或者斷電會丟失,Redis的數(shù)據(jù)也支持寫到硬盤中,這個過程就叫做持久化,文中有詳細的圖介紹,需要的朋友可以參考下
    2023-06-06
  • Redis中對大Key進行處理方式

    Redis中對大Key進行處理方式

    這篇文章主要介紹了Redis中對大Key進行處理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • Jedis操作Redis實現(xiàn)模擬驗證碼發(fā)送功能

    Jedis操作Redis實現(xiàn)模擬驗證碼發(fā)送功能

    Redis是一個著名的key-value存儲系統(tǒng),也是nosql中的最常見的一種,這篇文章主要給大家介紹Jedis操作Redis實現(xiàn)模擬驗證碼發(fā)送功能,感興趣的朋友一起看看吧
    2021-09-09
  • Redis底層數(shù)據(jù)結(jié)構(gòu)詳解

    Redis底層數(shù)據(jù)結(jié)構(gòu)詳解

    這篇文章主要介紹了Redis底層數(shù)據(jù)結(jié)構(gòu),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • Redis數(shù)據(jù)過期策略的實現(xiàn)詳解

    Redis數(shù)據(jù)過期策略的實現(xiàn)詳解

    最近項目當中遇到一個需求場景,需要清空一些存放在Redis的數(shù)據(jù),本文對Redis的過期機制簡單的講解一下,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論

龙胜| 枣阳市| 丹寨县| 沙雅县| 哈尔滨市| 宁德市| 时尚| 双鸭山市| 咸丰县| 东乡族自治县| 稻城县| 科技| 辽宁省| 榆社县| 监利县| 神木县| 历史| 新源县| 互助| 武川县| 寻乌县| 平邑县| 屏南县| 大宁县| 调兵山市| 当阳市| 怀仁县| 庆阳市| 西宁市| 虞城县| 阜南县| 涞水县| 凤阳县| 牟定县| 西吉县| 庄浪县| 泰安市| 西贡区| 大连市| 陆川县| 永仁县|