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

詳解MySQL和Redis如何保證數(shù)據(jù)一致性

 更新時(shí)間:2023年08月18日 09:14:48   作者:馬偉奇  
MySQL與Redis都是常用的數(shù)據(jù)存儲和緩存系統(tǒng),為了提高應(yīng)用程序的性能和可伸縮性,很多應(yīng)用程序?qū)ySQL和Redis一起使用,其中MySQL作為主要的持久存儲,而Redis作為主要的緩存,那么本文就給大家介紹一下MySQL和Redis如何保證數(shù)據(jù)一致性,需要的朋友可以參考下

什么是一致性

“數(shù)據(jù)一致”一般指的是:緩存中有數(shù)據(jù),緩存的數(shù)據(jù)值=數(shù)據(jù)庫中的值。但根據(jù)緩存中是有數(shù)據(jù)為依據(jù),則“一致”可以包含兩種情況:

1)緩存中有數(shù)據(jù),緩存的數(shù)據(jù)值=數(shù)據(jù)庫中的值。

2)緩存中本沒有數(shù)據(jù),數(shù)據(jù)庫中的值=最新值(有請求查詢數(shù)據(jù)庫時(shí),會將數(shù)據(jù)寫入緩存,則變?yōu)樯厦娴?ldquo;一致”狀態(tài))。

“數(shù)據(jù)不一致”:緩存的數(shù)據(jù)值≠數(shù)據(jù)庫中的值;緩存或者數(shù)據(jù)庫中存在舊值,導(dǎo)致其他線程讀到舊數(shù)據(jù)。

在這里插入圖片描述

一致性就是數(shù)據(jù)保持一致,在分布式系統(tǒng)中,可以理解為多個(gè)節(jié)點(diǎn)中數(shù)據(jù)的值是一致的。

  • 強(qiáng)一致性:這種一致性級別是最符合用戶直覺的,它要求系統(tǒng)寫入什么,讀出來的也會是什么,用戶體驗(yàn)好,但實(shí)現(xiàn)起來往往對系統(tǒng)的性能影響大
  • 弱一致性:這種一致性級別約束了系統(tǒng)在寫入成功后,不承諾立即可以讀到寫入的值,也不承諾多久之后數(shù)據(jù)能夠達(dá)到一致,但會盡可能地保證到某個(gè)時(shí)間級別(比如秒級別)后,數(shù)據(jù)能夠達(dá)到一致狀態(tài)
  • 最終一致性:最終一致性是弱一致性的一個(gè)特例,系統(tǒng)會保證在一定時(shí)間內(nèi),能夠達(dá)到一個(gè)數(shù)據(jù)一致的狀態(tài)。這里之所以將最終一致性單獨(dú)提出來,是因?yàn)樗侨跻恢滦灾蟹浅M瞥绲囊环N一致性模型,也是業(yè)界在大型分布式系統(tǒng)的數(shù)據(jù)一致性上比較推崇的模型

導(dǎo)致數(shù)據(jù)不一致的原因?

1) 在高并發(fā)的業(yè)務(wù)場景下,數(shù)據(jù)庫大多數(shù)情況都是用戶并發(fā)訪問最薄弱的環(huán)節(jié)。所以,就需要使用redis做一個(gè)緩沖操作,讓請求先訪問到redis,而不是直接訪問MySQL等數(shù)據(jù)庫;

2)讀取緩存步驟一般沒有什么問題,但是一旦涉及到數(shù)據(jù)更新,數(shù)據(jù)庫和緩存更新,就容易出現(xiàn)緩存(Redis)和數(shù)據(jù)庫(MySQL)間的數(shù)據(jù)一致性問題;

3)這個(gè)業(yè)務(wù)場景,主要是解決讀數(shù)據(jù)從Redis緩存,一般都是按照下圖的流程來進(jìn)行業(yè)務(wù)操作。

在這里插入圖片描述

應(yīng)對策略

針對緩存更新問題,提出了一個(gè)旁路緩存的緩存更新套路,這個(gè)策略分為以下三種場景:

1)失效:應(yīng)用程序先從緩存取數(shù)據(jù),沒有得到,則從數(shù)據(jù)庫中取數(shù)據(jù),成功后,放到緩存中。

2)命中:應(yīng)用程序從緩存中取數(shù)據(jù),取到后返回。

3)更新:先把數(shù)據(jù)存到數(shù)據(jù)庫中,成功后,再讓緩存失效。

不管是先刪緩存再更新數(shù)據(jù)庫還是先更新數(shù)據(jù)庫再刪緩存,都會導(dǎo)致緩存跟數(shù)據(jù)不一致問題!

先寫MySQL,再寫Redis

在這里插入圖片描述

先寫Redis,再寫MySQL

在這里插入圖片描述

先刪除Redis,再寫MySQL

在這里插入圖片描述

先寫 MySQL,再刪除 Redis

在這里插入圖片描述

不管是先寫數(shù)據(jù)庫,再刪除緩存;還是先刪除緩存,再寫庫,都有可能出現(xiàn)數(shù)據(jù)不一致的情況。

現(xiàn)有的大部分業(yè)務(wù)場景下大多采用讀寫分離的操作來提升數(shù)據(jù)庫吞吐量,但是并發(fā)讀寫訪問的時(shí)候,對緩存和數(shù)據(jù)庫相互交叉執(zhí)行操作,則會出現(xiàn)數(shù)據(jù)不一致問題。

在進(jìn)行數(shù)據(jù)更新時(shí),就涉及到先更新緩存還是先更新數(shù)據(jù)庫了,其實(shí)兩種方式都有數(shù)據(jù)一致性問題:

舉個(gè)例子:假如業(yè)務(wù)A為寫請求,業(yè)務(wù)B為讀請求

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

步驟1:業(yè)務(wù)A先更新數(shù)據(jù)庫,此時(shí)該業(yè)務(wù)線由于宕機(jī)或者其他原因延遲沒有繼續(xù)進(jìn)行。

步驟2:業(yè)務(wù)B讀取數(shù)據(jù),讀取的是緩存中的舊數(shù)據(jù)。

步驟3:業(yè)務(wù)A恢復(fù)過來,更新緩存

可以看到,由于寫請求延遲,可能會讀到舊的緩存數(shù)據(jù)。

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

步驟1:業(yè)務(wù)A先刪除緩存

步驟2:業(yè)務(wù)B進(jìn)入,業(yè)務(wù)B發(fā)現(xiàn)緩存中沒有數(shù)據(jù),直接從數(shù)據(jù)庫中進(jìn)行讀取,讀到了數(shù)據(jù)庫中的舊數(shù)據(jù)

步驟3:業(yè)務(wù)A更新數(shù)據(jù)庫并返回。

可以看到,由于寫請求延遲,可能讀到舊的數(shù)據(jù)庫數(shù)據(jù)。

因?yàn)閷懞妥x是并發(fā)的,沒法保證順序,就會出現(xiàn)緩存和數(shù)據(jù)庫的數(shù)據(jù)不一致的問題。

解決方案

(1)讀寫請求串行化

最為簡單的一種方法,寫請求在更新之前需要先獲得分布式鎖,獲取到鎖才能去更新數(shù)據(jù)庫,獲取不到則進(jìn)行等待,超時(shí)直接返回更新失敗。更新完數(shù)據(jù)庫后更新緩存,如果更新失敗,放到內(nèi)存隊(duì)列中進(jìn)行重新嘗試。讀請求則同樣需要獲得鎖,然判斷緩存中是否有數(shù)據(jù),有則直接讀緩存,沒有則直接讀數(shù)據(jù)庫,并更新緩存。

這種方案可以保證數(shù)據(jù)的一致性。但是會降低系統(tǒng)吞吐量(等待時(shí)間長),這在需要數(shù)據(jù)強(qiáng)一致的情況下適用。(銀行轉(zhuǎn)賬)

(2)刪除緩存

  • 1.先刪除緩存,后更新數(shù)據(jù)庫
  • 2.先更新數(shù)據(jù)庫,后刪除緩存

先刪除緩存,后更新數(shù)據(jù)庫,第二步操作失敗,數(shù)據(jù)庫沒有更新成功,那下次讀緩存發(fā)現(xiàn)不存在則從數(shù)據(jù)庫中讀取,并重建緩存,此時(shí)數(shù)據(jù)庫和緩存依日保持一致。

但如果是先更新數(shù)據(jù)庫,后刪除緩存,第二步操作失敗,數(shù)據(jù)庫是最新值,緩存中是舊值,發(fā)生不致。所以,這個(gè)方案依舊存在問題。

總之,和前面提到的問題類似,第二步失敗依舊有不一致的風(fēng)險(xiǎn)

我們再來看[并發(fā)]問題,這個(gè)問題是我們需要關(guān)注的[重點(diǎn)]

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

依舊是 2 個(gè)線程并發(fā)[讀寫]數(shù)據(jù)

1.緩存中 X 不存在 (數(shù)據(jù)庫 X = 1)

2.線程 A 讀取數(shù)據(jù)庫,得到目值 (X = 1)

3.線程 B 更新數(shù)據(jù)庫 (X = 2)

4.線程 B 刪除緩存

5.線程 A 將日值寫入緩存 (X = 1)

最終 X的值在緩存中是 1 (日值) ,在數(shù)據(jù)庫中是 2(新值),也發(fā)生不一致

這種情況[理論]來說是可能發(fā)生的,但實(shí)際真的有可能發(fā)生嗎?

其實(shí)概率[很低],這是因?yàn)樗仨殱M足 3 個(gè)條件

1.緩存剛好已失效

2.讀請求 + 寫請求并發(fā)

3.更新數(shù)據(jù)庫 + 除緩存的時(shí)間 (步 3-4) ,要比讀數(shù)據(jù)庫 + 寫緩存時(shí)間短(步 2 和5)

仔細(xì)想一下,條件 3 發(fā)生的概率其實(shí)是非常低的因?yàn)閷憯?shù)據(jù)庫一般會先[加鎖],所以寫數(shù)據(jù)庫,通常是要比讀數(shù)據(jù)庫的時(shí)間更長的這么來看,[先更新數(shù)據(jù)庫 + 再刪除緩存]的方案,是可以保證數(shù)據(jù)一致性的。

所以,我們應(yīng)該采用這種方案,來操作數(shù)據(jù)庫和緩存

如何保證兩步都執(zhí)行成功?

無論是更新緩存還是刪除緩存,只要第二步發(fā)生失敗,那么就會導(dǎo)致數(shù)據(jù)庫和緩存不一致。保證第二步成功執(zhí)行,就是解決問題的關(guān)鍵.

程序在執(zhí)行過程中發(fā)生異常,最簡單的解決辦法是什么?

答案是:異步重試

  • 如果是同步重試,立即重試很大概率還會失敗,[重試次數(shù)]設(shè)置多少才合理?
  • 重試會一直[占用]這個(gè)線程資源,無法服務(wù)其它客戶端請求
  • 異步其實(shí)就是把重試請求寫到消息隊(duì)列中,然后由專門的消費(fèi)者來重試,直到成功。

為了避免第二步執(zhí)行失敗,我們可以把操作緩存這一步,直接放到消息隊(duì)列中,由消費(fèi)者來操作緩存

到這里你可能會問,寫消息隊(duì)列也有可能會失敗啊? 而且,引入消息隊(duì)列,這又增加了更多的維擴(kuò)成本,這樣做值得嗎?

這個(gè)問題很好,但我們思考這樣一個(gè)問題:如果在執(zhí)行失敗的線程中一直重試,還沒等執(zhí)行成功,此時(shí)如果項(xiàng)目[重啟]了,那這次重試請求也就[丟失]了,那這條數(shù)據(jù)就一直不一致了

所以,這里我們必須把重試消息或第二步操作放到另一個(gè)[服務(wù)]中,這個(gè)服務(wù)用[消息隊(duì)列]最為合適。

  • 消息隊(duì)列保證可靠性: 寫到隊(duì)列中的消息,成功消費(fèi)之前不會丟失(重啟項(xiàng)目也不擔(dān)心)
  • 消息隊(duì)列保證消息成功投遞: 下游從隊(duì)列拉取消息,成功消費(fèi)后才會刪除消息,否則還會繼續(xù)投遞消息給消費(fèi)者 (符合我們重試的需求)

至于寫隊(duì)列失敗和消息隊(duì)列的維護(hù)成本問題

  • 寫隊(duì)列失敗: 操作緩存和寫消息隊(duì)列,[同時(shí)失敗]的概率其實(shí)是很小的維護(hù)成本:
  • 我們項(xiàng)目中一般都會用到消息隊(duì)列,維護(hù)成本并沒有新增很多

以上就是詳解MySQL和Redis如何保證數(shù)據(jù)一致性的詳細(xì)內(nèi)容,更多關(guān)于MySQL和Redis數(shù)據(jù)一致性的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • mysql charset=utf8你真的弄明白意思了嗎

    mysql charset=utf8你真的弄明白意思了嗎

    這篇文章主要介紹了mysql charset=utf8你真的弄明白意思了嗎?文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • MySQL在Windows上安裝的詳細(xì)流程

    MySQL在Windows上安裝的詳細(xì)流程

    MySQL 是最流行的數(shù)據(jù)庫管理系統(tǒng) (DBMS) 之一,它輕量、開源且易于安裝和使用,因此對于那些剛開始學(xué)習(xí)和使用關(guān)系數(shù)據(jù)庫的人來說是一個(gè)不錯的選擇, 本文主要系統(tǒng)介紹Windows的環(huán)境下MySQL的安裝過程和驗(yàn)證過程,需要的朋友可以參考下
    2024-12-12
  • MySQL中讀頁緩沖區(qū)buffer?pool詳解

    MySQL中讀頁緩沖區(qū)buffer?pool詳解

    這篇文章主要介紹了MySQL中讀頁緩沖區(qū)buffer?pool?,從磁盤中讀取數(shù)據(jù)到內(nèi)存的過程是十分慢的,所以我們讀取的頁面需要將其緩存起來,所以MySQL有這個(gè)buffer pool對頁面進(jìn)行緩存,需要的朋友可以參考下
    2022-05-05
  • MySQL進(jìn)行表之間關(guān)聯(lián)更新的實(shí)現(xiàn)方法

    MySQL進(jìn)行表之間關(guān)聯(lián)更新的實(shí)現(xiàn)方法

    在實(shí)際編程工作或運(yùn)維實(shí)踐中,對MySQL數(shù)據(jù)庫表進(jìn)行關(guān)聯(lián)更新是一種比較常見的應(yīng)用場景,針對這樣的業(yè)務(wù)場景,我們來看看有什么方法可以實(shí)現(xiàn)關(guān)聯(lián)更新,需要的朋友可以參考下
    2023-10-10
  • mysql中decimal數(shù)據(jù)類型小數(shù)位填充問題詳解

    mysql中decimal數(shù)據(jù)類型小數(shù)位填充問題詳解

    這篇文章主要介紹了mysql中decimal數(shù)據(jù)類型小數(shù)位填充問題詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Linux安裝MySQL的教程

    Linux安裝MySQL的教程

    這篇文章主要介紹了Linux安裝MySQL的教程,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • MySQL可直接使用的查詢表的列信息(實(shí)現(xiàn)方案)

    MySQL可直接使用的查詢表的列信息(實(shí)現(xiàn)方案)

    本文介紹了如何使用SQL快速將下劃線命名的表字段轉(zhuǎn)換為駝峰命名格式,包括確定下劃線位置、找到第一個(gè)字符、截取并拼接字符串等步驟,通過使用LOCATE、CONCAT、UCASE和LOWER等函數(shù),可以實(shí)現(xiàn)高效的字段命名轉(zhuǎn)換,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • 詳解MySQL 8.0 之不可見索引

    詳解MySQL 8.0 之不可見索引

    這篇文章主要介紹了MySQL 8.0 之不可見索引的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)新版本的MySQL,感興趣的朋友可以了解下
    2020-10-10
  • mysql之跨庫關(guān)聯(lián)查詢(dblink)問題

    mysql之跨庫關(guān)聯(lián)查詢(dblink)問題

    這篇文章主要介紹了mysql之跨庫關(guān)聯(lián)查詢(dblink)問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • MySQL查看鎖表的實(shí)現(xiàn)步驟

    MySQL查看鎖表的實(shí)現(xiàn)步驟

    在MySQL數(shù)據(jù)庫中,當(dāng)多個(gè)事務(wù)同時(shí)請求對同一行數(shù)據(jù)進(jìn)行修改時(shí),就會發(fā)生鎖表現(xiàn)象,本文主要介紹了MySQL查看鎖表的實(shí)現(xiàn)步驟,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01

最新評論