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

Redis與MySQL的雙寫一致性問題

 更新時(shí)間:2023年03月27日 16:41:01   作者:小熊不吃香菜  
這篇文章只要介紹了Redis與MySQL雙寫一致性,主要是指在使用緩存和數(shù)據(jù)庫同時(shí)存儲數(shù)據(jù)的場景下( 主要是存在高并發(fā)的情況),如何保證兩者的數(shù)據(jù)一致性(內(nèi)容相同或者盡可能接近),感興趣的同學(xué)可以借鑒一下

Redis與MySQL雙寫一致性是指在使用緩存和數(shù)據(jù)庫同時(shí)存儲數(shù)據(jù)的場景下( 主要是存在高并發(fā)的情況),如何保證兩者的數(shù)據(jù)一致性(內(nèi)容相同或者盡可能接近)。

 正常業(yè)務(wù)流程

讀沒什么問題,關(guān)鍵就在于寫(更新)操作,這就會出現(xiàn)幾個(gè)問題了,這里是先更新數(shù)據(jù)庫,然后對緩存操作。但對于緩存操作,是更新緩存還是刪除緩存呢?或者為什么不是先操作(刪除、更新)緩存在更新數(shù)據(jù)庫呢?

總結(jié)一下就是到底先操作緩存再操作數(shù)據(jù)庫,還是先操作數(shù)據(jù)庫再操作緩存?

帶著這幾個(gè)問題接著往下講。

首先講一下操作緩存,包括兩種:更新緩存和刪除緩存,如何選擇?

更新緩存? 刪除緩存?

假設(shè)都先更新數(shù)據(jù)庫(因?yàn)橄炔僮骶彺嬖俨僮鲾?shù)據(jù)庫問題較大,后面會講)

  •  更新緩存

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

如果兩個(gè)請求同時(shí)對同一條數(shù)據(jù)進(jìn)行修改,那么可能出現(xiàn)先后順序顛倒,導(dǎo)致緩存中的數(shù)據(jù)是舊的。之后的讀請求讀到的都是舊數(shù)據(jù),只有當(dāng)緩存失效后,才能從數(shù)據(jù)庫中得到正確的值。

  • 刪除緩存

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

會有這樣一種情況:緩存剛好失效,請求B從數(shù)據(jù)庫中查詢數(shù)據(jù),得到舊值。此時(shí)請求A更新數(shù)據(jù)庫,將新值寫入數(shù)據(jù)庫,并刪除緩存。而請求B又將舊值寫入緩存中,導(dǎo)致臟數(shù)據(jù)

從上面看出現(xiàn)臟數(shù)據(jù)的要求要比更新緩存的要求更多,必須滿足以下幾個(gè)條件:

  1. 緩存失效
  2. 讀請求 + 寫請求并發(fā)
  3. 更新數(shù)據(jù)庫 + 刪除緩存的時(shí)間要比讀數(shù)據(jù)庫 + 寫緩存時(shí)間

前面兩個(gè)很好滿足,我們再看看第三點(diǎn),這個(gè)真的會出現(xiàn)嗎?

數(shù)據(jù)庫在更新時(shí)一般是加鎖的,讀操作的速度遠(yuǎn)快于寫操作的,所以第三點(diǎn)發(fā)生概率極低(當(dāng)然也可能發(fā)生)

注:這里我其實(shí)不是很理解,單純看確實(shí)發(fā)生概率低,但如果出現(xiàn)網(wǎng)絡(luò)延遲等情況呢,不也會發(fā)生嗎?希望好心人解惑,我反正沒理解。

因此,在選擇刪除緩存時(shí),還需要結(jié)合其他技術(shù)來優(yōu)化性能和一致性。例如:

  • 使用消息隊(duì)列來異步地刪除或更新緩存,避免阻塞主線程或者丟失消息。
  • 使用延時(shí)雙刪來增加刪除成功率和減少不一致時(shí)間窗口。即在更新數(shù)據(jù)庫后立即刪除一次緩存,并在一定時(shí)間間隔后再次刪除一次。

 對比

在更新緩存中, 每次去更新緩存,但是緩存中的數(shù)據(jù)不一定會被馬上讀取,這就會導(dǎo)致緩存中可能存放了很多不常訪問的數(shù)據(jù),浪費(fèi)緩存資源。而且很多情況下,寫到緩存中的值,并不是與數(shù)據(jù)庫中的值一一對應(yīng)的,很有可能是先查詢數(shù)據(jù)庫,再經(jīng)過一系列「計(jì)算」得出一個(gè)值,才把這個(gè)值才寫到緩存中。

? 由此可見,這種更新緩存的方案,不僅緩存利用率不高,還會造成機(jī)器性能的浪費(fèi)。所以我們一般考慮刪除緩存

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

在更新數(shù)據(jù)時(shí),先將新數(shù)據(jù)寫入緩存(Redis),再將新數(shù)據(jù)寫入數(shù)據(jù)庫(MySQL)

 但其存在一下問題:

  • 緩存更新成功,但數(shù)據(jù)庫更新失敗,導(dǎo)致數(shù)據(jù)不一致

 :用戶修改了自己的昵稱,系統(tǒng)先將新的昵稱寫入緩存,然后再更新數(shù)據(jù)庫。但是在更新數(shù)據(jù)庫的過程中,發(fā)生了網(wǎng)絡(luò)故障或者數(shù)據(jù)庫宕機(jī)等異常情況,導(dǎo)致數(shù)據(jù)庫中的昵稱沒有被修改。這樣就會出現(xiàn)緩存中的昵稱和數(shù)據(jù)庫中的昵稱不一致的情況。

  • 緩存更新成功,但數(shù)據(jù)庫更新延遲,導(dǎo)致其他請求讀取到舊的數(shù)據(jù)

 :用戶下單了一個(gè)商品,系統(tǒng)先將訂單狀態(tài)寫入緩存,然后再更新數(shù)據(jù)庫。但是在更新數(shù)據(jù)庫的過程中,由于并發(fā)量大或者其他原因,導(dǎo)致數(shù)據(jù)庫的寫入速度慢于緩存的寫入速度。這樣就會出現(xiàn)其他請求從緩存中讀取到訂單狀態(tài)為已支付,而從數(shù)據(jù)庫中讀取到訂單狀態(tài)為未支付的情況。

  • 緩存更新成功,但在數(shù)據(jù)庫更新之前有其他請求查詢了緩存和數(shù)據(jù)庫,并將舊的數(shù)據(jù)寫回緩存,覆蓋了新的數(shù)據(jù)

 例:用戶A修改了自己的頭像,并上傳到服務(wù)器上。系統(tǒng)先將新的頭像地址寫入緩存,并返回給用戶A顯示。然后再將新的頭像地址更新到數(shù)據(jù)庫中。但是在這個(gè)過程中,用戶B訪問了用戶A的個(gè)人主頁,并從緩存中讀取到了新的頭像地址。由于緩存失效策略或者其他原因(比如重啟),導(dǎo)致緩存被清空或者過期。這時(shí)候用戶B再次訪問用戶A 的個(gè)人主頁,并從數(shù)據(jù)庫中讀取到了舊的頭像地址,并將其寫回緩存中。這樣就會出現(xiàn)緩存中 的頭像地址和 數(shù)據(jù)庫 中 的頭像地址不一致 的情況。

上面說了一堆,其實(shí)總結(jié)就是緩存更新成功了,數(shù)據(jù)庫沒更新(更新失?。?/strong>,導(dǎo)致緩存存的是最新值,數(shù)據(jù)庫存的是舊值。如果緩存失效了,就會拿到數(shù)據(jù)庫中的舊值。

 后面我自己也搞疑惑了,既然是因?yàn)閿?shù)據(jù)庫更新失敗導(dǎo)致的問題,那我是不是只要保證數(shù)據(jù)庫更新成功就可以解決數(shù)據(jù)不一致的問題,當(dāng)數(shù)據(jù)庫更新失敗時(shí),不停的重試更新數(shù)據(jù)庫,直到數(shù)據(jù)庫更新完成。

后面發(fā)現(xiàn)自己太天真,其中存在很多問題,比如:

  • 如果數(shù)據(jù)庫更新失敗的原因是數(shù)據(jù)庫宕機(jī)或者網(wǎng)絡(luò)故障,那么你不停地重試更新數(shù)據(jù)庫可能會造成更大的壓力和延遲,甚至導(dǎo)致數(shù)據(jù)庫恢復(fù)困難。
  • 如果數(shù)據(jù)庫更新失敗的原因是數(shù)據(jù)沖突或者業(yè)務(wù)邏輯錯誤,那么你不停地重試更新數(shù)據(jù)庫可能會導(dǎo)致數(shù)據(jù)丟失或者數(shù)據(jù)錯亂,甚至影響其他用戶的數(shù)據(jù)。
  • 如果你不停地重試更新數(shù)據(jù)庫,那么你需要考慮如何保證重試的冪等性和順序性,以及如何處理重試過程中發(fā)生的異常情況。

 所以,這種方法并不是一個(gè)很好的解決方案。

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

當(dāng)有一個(gè)更新操作時(shí),先更新數(shù)據(jù)庫數(shù)據(jù),然后再更新對應(yīng)的緩存數(shù)據(jù)

 但是,這種方案也有一些問題和風(fēng)險(xiǎn),比如:

  • 如果更新數(shù)據(jù)庫成功了,但是更新緩存失敗了,那么就會導(dǎo)致緩存中就會保留舊的數(shù)據(jù),而數(shù)據(jù)庫中已經(jīng)是新的數(shù)據(jù),即臟數(shù)據(jù)。
  • 如果在更新數(shù)據(jù)庫和更新緩存之間,有其他請求查詢了同一個(gè)數(shù)據(jù),并且發(fā)現(xiàn)緩存存在,那么就會從緩存中讀取舊的數(shù)據(jù)。這樣也會造成緩存和數(shù)據(jù)庫之間的不一致性。

 因此,在使用更新緩存操作時(shí),無論誰先誰后,但凡后者發(fā)生異常,就會對業(yè)務(wù)造成影響。(還是上面那張圖)

那么如何處理異常情況來保證數(shù)據(jù)一致性呢

這些問題的源頭都是多線程并發(fā)所導(dǎo)致的,所以最簡單的方法就是加鎖(分布式鎖)。兩個(gè)線程要修改同一條數(shù)據(jù),每個(gè)線程在改之前,先去申請分布式鎖,拿到鎖的線程才允許更新數(shù)據(jù)庫和緩存,拿不到鎖的線程,返回失敗,等待下次重試。這么做的目的,就是為了只允許一個(gè)線程去操作數(shù)據(jù)和緩存,避免并發(fā)問題。

? 但加鎖費(fèi)時(shí)費(fèi)力,肯定不推薦。并且,每次去更新緩存,但是緩存中的數(shù)據(jù)不一定會被馬上讀取,這就會導(dǎo)致緩存中可能存放了很多不常訪問的數(shù)據(jù),浪費(fèi)緩存資源。而且很多情況下,寫到緩存中的值,并不是與數(shù)據(jù)庫中的值一一對應(yīng)的,很有可能是先查詢數(shù)據(jù)庫,再經(jīng)過一系列「計(jì)算」得出一個(gè)值,才把這個(gè)值才寫到緩存中。

? 由此可見,這種更新數(shù)據(jù)庫 + 更新緩存的方案,不僅緩存利用率不高,還會造成機(jī)器性能的浪費(fèi)。

所以此時(shí)我們需要考慮另外一種方案:刪除緩存

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

當(dāng)有一個(gè)更新操作時(shí),先刪除對應(yīng)的緩存數(shù)據(jù),然后再更新數(shù)據(jù)庫數(shù)據(jù)

 但是,這種方案也有一些問題和風(fēng)險(xiǎn),比如:

  • 如果刪除緩存后,更新數(shù)據(jù)庫失敗了,那么就會導(dǎo)致緩存丟失,下次查詢時(shí)需要重新從數(shù)據(jù)庫加載數(shù)據(jù),增加了數(shù)據(jù)庫壓力和響應(yīng)時(shí)間。
  • 如果在刪除緩存和更新數(shù)據(jù)庫之間,有其他請求查詢了同一個(gè)數(shù)據(jù),并且發(fā)現(xiàn)緩存不存在,那么就會從數(shù)據(jù)庫中讀取舊的數(shù)據(jù),并寫入到緩存中。這樣就會造成緩存和數(shù)據(jù)庫之間的不一致性。

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

當(dāng)有一個(gè)更新操作時(shí),先更新數(shù)據(jù)庫數(shù)據(jù),再刪除緩存

上面其實(shí)講過了,我再重復(fù)一遍吧

會有這樣一種情況:緩存剛好失效,請求B從數(shù)據(jù)庫中查詢數(shù)據(jù),得到舊值。此時(shí)請求A更新數(shù)據(jù)庫,將新值寫入數(shù)據(jù)庫,并刪除緩存。而請求B又將舊值寫入緩存中,導(dǎo)致臟數(shù)據(jù)

從上面看出現(xiàn)臟數(shù)據(jù)的要求要比更新緩存的要求更多,必須滿足以下幾個(gè)條件:

  1. 緩存失效
  2. 讀請求 + 寫請求并發(fā)
  3. 更新數(shù)據(jù)庫 + 刪除緩存的時(shí)間要比讀數(shù)據(jù)庫 + 寫緩存時(shí)間

前面兩個(gè)很好滿足,我們再看看第三點(diǎn),這個(gè)真的會出現(xiàn)嗎?

數(shù)據(jù)庫在更新時(shí)一般是加鎖的,讀操作的速度遠(yuǎn)快于寫操作的,所以第三點(diǎn)發(fā)生概率極低

所以,解決雙寫問題更適合的方法是先更新數(shù)據(jù)庫,再刪除緩存,當(dāng)然具體場景具體分析,不定說一定就是這個(gè)。

講解了這些操作后會出現(xiàn)的問題,那么為了避免這些問題,如何做呢?

  • 先刪除緩存再更新數(shù)據(jù)庫,然后使用異步線程或消息隊(duì)列來重建緩存。
  • 先更新數(shù)據(jù)庫再刪除緩存,并設(shè)置一個(gè)合理的過期時(shí)間來保證緩存的有效性。
  • 使用分布式鎖或樂觀鎖來控制并發(fā)訪問,并保證每次只有一個(gè)請求能夠操作緩存和數(shù)據(jù)庫

 ……

下面講幾種常見的方法以保證雙寫一致性

解決方案

1. 重試

上面也提到過,當(dāng)?shù)诙讲僮魇r(shí),我就重試嘛,盡可能地補(bǔ)救,但重試的成本太大,上面講過就不重復(fù)了。

2. 異步重試

? 既然重試方法占用資源,那我就做異步。在刪除或更新緩存時(shí),如果操作失敗,不立即返回錯誤,而是通過一些機(jī)制(如消息隊(duì)列、定時(shí)任務(wù)、訂閱binlog等)來觸發(fā)緩存的重試操作。這樣可以避免同步重試緩存時(shí)的性能損耗和阻塞問題,但也可能導(dǎo)致緩存和數(shù)據(jù)庫的數(shù)據(jù)不一致的時(shí)間較長。

2.1 使用消息隊(duì)列實(shí)現(xiàn)重試

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

使用消息隊(duì)列異步重試緩存的情況是指,當(dāng)信息發(fā)生變化時(shí),先更新數(shù)據(jù)庫,然后刪緩存,如果刪除成功就皆大歡喜,如果刪除失敗,則將需要刪除的key發(fā)送到消息隊(duì)列。另外有一個(gè)消費(fèi)者線程從消息隊(duì)列中獲取要刪除的key,并根據(jù)key刪除或更新Redis中的緩存。如果操作失敗,則重新發(fā)送到消息隊(duì)列中進(jìn)行重試。

注:也可以不先嘗試刪除,直接發(fā)送給消息隊(duì)列,讓消息隊(duì)列

舉例來說,假設(shè)有一個(gè)用戶信息表,需要將用戶信息緩存在Redis中。如果采用使用消息隊(duì)列異步重試緩存的方案,可以有以下幾個(gè)步驟:

  • 當(dāng)用戶信息發(fā)生變化時(shí),先更新數(shù)據(jù)庫,并返回成功結(jié)果給前端。
  • 嘗試去刪除緩存,成功則結(jié)束操作,失敗則將要刪除或更新緩存的操作生成一個(gè)消息(比如包含key和操作類型),并發(fā)送到消息隊(duì)列中(比如使用Kafka或RabbitMQ)。
  • 另外有一個(gè)消費(fèi)者線程從消息隊(duì)列中訂閱并獲取這些消息,并根據(jù)消息內(nèi)容刪除或更新Redis中的對應(yīng)信息。
  • 如果刪除或更新緩存成功,則把這個(gè)消息從消息隊(duì)列中移除(丟棄),以免重復(fù)操作。
  • 如果刪除或更新緩存失敗,則執(zhí)行失敗策略,比如設(shè)置一個(gè)延遲時(shí)間或者一個(gè)重試次數(shù)限制,然后重新發(fā)送這個(gè)消息到消息隊(duì)列中進(jìn)行重試。
  • 如果重試超過一定次數(shù)仍然失敗,則向業(yè)務(wù)層發(fā)送報(bào)錯信息,并記錄日志。

2.2 Binlog實(shí)現(xiàn)異步重試刪除

使用binlog實(shí)現(xiàn)一致性的基本思路是利用binlog日志來記錄數(shù)據(jù)庫的變更操作,然后通過主從復(fù)制或者增量備份的方式來同步或者恢復(fù)數(shù)據(jù)。

舉例來說,如果我們有一個(gè)主數(shù)據(jù)庫和一個(gè)從數(shù)據(jù)庫,我們可以在主數(shù)據(jù)庫上開啟binlog日志,并設(shè)置從數(shù)據(jù)庫作為它的復(fù)制節(jié)點(diǎn)。這樣,當(dāng)主數(shù)據(jù)庫上發(fā)生任何變更操作時(shí),它會將對應(yīng)的binlog日志發(fā)送給從數(shù)據(jù)庫,從數(shù)據(jù)庫則會根據(jù)binlog日志來執(zhí)行相同的操作,從而保證數(shù)據(jù)一致性。

另外,如果我們需要恢復(fù)某個(gè)時(shí)間點(diǎn)之前的數(shù)據(jù),我們也可以利用binlog日志來實(shí)現(xiàn)。首先,我們需要找到對應(yīng)時(shí)間點(diǎn)之前的最近一個(gè)全量備份文件,并將其恢復(fù)到目標(biāo)數(shù)據(jù)庫。然后,我們需要找到對應(yīng)時(shí)間點(diǎn)之前的所有增量備份文件(即binlog日志文件),并按照順序?qū)⑵鋺?yīng)用到目標(biāo)數(shù)據(jù)庫。這樣,我們就可以恢復(fù)出目標(biāo)時(shí)間點(diǎn)之前的數(shù)據(jù)狀態(tài)了。

  • 使用 Binlog 實(shí)時(shí)更新/刪除 Redis 緩存。利用 Canal,即將負(fù)責(zé)更新緩存的服務(wù)偽裝成一個(gè) MySQL 的從節(jié)點(diǎn),從 MySQL 接收 Binlog,解析 Binlog 之后,得到實(shí)時(shí)的數(shù)據(jù)變更信息,然后根據(jù)變更信息去更新/刪除 Redis 緩存;
  • MQ+Canal 策略,將 Canal Server 接收到的 Binlog 數(shù)據(jù)直接投遞到 MQ 進(jìn)行解耦,使用 MQ 異步消費(fèi) Binlog 日志,以此進(jìn)行數(shù)據(jù)同步;

注:binlog日志是MySQL的二進(jìn)制日志,它記錄了對數(shù)據(jù)庫的變更操作,比如插入、更新、刪除等。 binlog日志有兩個(gè)主要作用,一個(gè)是主從復(fù)制,另一個(gè)是增量備份。

主從復(fù)制是指在一個(gè)主數(shù)據(jù)庫和一個(gè)或多個(gè)從數(shù)據(jù)庫之間實(shí)現(xiàn)數(shù)據(jù)的同步。主數(shù)據(jù)庫會將自己的binlog日志發(fā)送給從數(shù)據(jù)庫,從數(shù)據(jù)庫則會根據(jù)binlog日志來執(zhí)行相同的操作,從而保證數(shù)據(jù)一致性。這樣可以提高數(shù)據(jù)的可用性和可靠性,也可以實(shí)現(xiàn)負(fù)載均衡和故障轉(zhuǎn)移。

增量備份是指在全量備份的基礎(chǔ)上,定期備份數(shù)據(jù)庫的變更操作。全量備份是指將整個(gè)數(shù)據(jù)庫的數(shù)據(jù)完整地備份到一個(gè)文件中。增量備份則是指將每次變更操作對應(yīng)的binlog日志文件備份到另一個(gè)文件中。這樣可以減少備份所占用的空間和時(shí)間,也可以實(shí)現(xiàn)靈活地恢復(fù)數(shù)據(jù)到任意時(shí)間點(diǎn)。

至此,我們可以得出結(jié)論,想要保證數(shù)據(jù)庫和緩存一致性,推薦采用「先更新數(shù)據(jù)庫,再刪除緩存」方案,并配合「消息隊(duì)列」或「訂閱變更日志」的方式來做。

3. 延時(shí)雙刪

我們重點(diǎn)在將先更新數(shù)據(jù)庫,在刪除緩存。那如果我要先刪除緩存,再更新數(shù)據(jù)庫呢?

回顧之前講的先刪除緩存,再更新數(shù)據(jù)庫,它會出現(xiàn)舊值覆蓋緩存的問題,那好辦,我們直接把這個(gè)舊值給刪了不就完了嗎,延時(shí)雙刪就是這個(gè)原理,它的基本思路是:

  1. 先刪除緩存
  2. 再更新數(shù)據(jù)庫
  3. 休眠一段時(shí)間(根據(jù)系統(tǒng)情況確定)
  4. 再次刪除緩存

這樣做的目的是為了防止在更新數(shù)據(jù)庫后,有其他線程讀取到舊的緩存數(shù)據(jù),并將其寫回緩存,導(dǎo)致數(shù)據(jù)不一致。

舉個(gè)例子:假設(shè)有一個(gè)用戶信息表,其中有一個(gè)字段是用戶積分?,F(xiàn)在有兩個(gè)線程A和B同時(shí)對用戶積分進(jìn)行操作:

  • 線程A要給用戶增加100積分
  • 線程B要給用戶減少50積分

如果使用延時(shí)雙刪策略,那么線程A和B的執(zhí)行過程可能如下:

  • 線程A先刪除緩存中的用戶信息
  • 線程A再從數(shù)據(jù)庫中讀取用戶信息,發(fā)現(xiàn)用戶積分為1000
  • 線程A將用戶積分加上100,變?yōu)?100,并更新到數(shù)據(jù)庫中
  • 線程A休眠5秒(假設(shè)這個(gè)時(shí)間足夠讓數(shù)據(jù)庫同步)
  • 線程A再次刪除緩存中的用戶信息
  • 線程B先刪除緩存中的用戶信息
  • 線程B再從數(shù)據(jù)庫中讀取用戶信息,發(fā)現(xiàn)用戶積分為1100(因?yàn)榫€程A已經(jīng)更新了)
  • 線程B將用戶積分減去50,變?yōu)?050,并更新到數(shù)據(jù)庫中
  • 線程B休眠5秒(假設(shè)這個(gè)時(shí)間足夠讓數(shù)據(jù)庫同步)
  • 線程B再次刪除緩存中的用戶信息

這樣最終結(jié)果就是:數(shù)據(jù)庫中的用戶積分為1050,緩存中沒有該用戶信息。當(dāng)下次有請求查詢該用戶信息時(shí),就會從數(shù)據(jù)庫中讀取并寫入到緩存中。這樣就保證了數(shù)據(jù)一致性。

延時(shí)雙刪適用于高并發(fā)場景,特別是對數(shù)據(jù)的修改操作比較頻繁,而查詢操作比較少的情況。這樣可以減輕數(shù)據(jù)庫的壓力,提高性能,同時(shí)保證數(shù)據(jù)的最終一致性。延時(shí)雙刪也適用于數(shù)據(jù)庫有主從同步延遲的場景,因?yàn)樗梢员苊庠诟聰?shù)據(jù)庫后,從庫還沒有同步完成時(shí),讀取到舊的緩存數(shù)據(jù),并將其寫回緩存。

注: 這個(gè)休眠時(shí)間 = 讀業(yè)務(wù)邏輯數(shù)據(jù)的耗時(shí) + 幾百毫秒。 為了確保讀請求結(jié)束,寫請求可以刪除讀請求可能帶來的緩存臟數(shù)據(jù)。

總結(jié)

好了,總結(jié)一下這篇文章的重點(diǎn)。

Redis與MySQL的雙寫一致性問題是指在使用緩存和數(shù)據(jù)庫同時(shí)存儲數(shù)據(jù)的場景下,如何保證兩者的數(shù)據(jù)一致性。這個(gè)問題主要涉及到以下幾個(gè)方面:

  • 緩存更新策略:緩存更新策略有三種,分別是先更新緩存再更新數(shù)據(jù)庫,先更新數(shù)據(jù)庫再更新緩存,先刪除緩存再更新數(shù)據(jù)庫 和先更新數(shù)據(jù)庫再刪除緩存。每種策略都有可能導(dǎo)致數(shù)據(jù)不一致的情況。
  • 數(shù)據(jù)庫主從同步延遲:如果使用了主從復(fù)制模式來提高數(shù)據(jù)庫的可用性和讀寫分離能力,那么就可能存在主從同步延遲的問題。也就是說,在主庫上執(zhí)行了寫操作后,并不會立即同步到從庫上。這樣,在讀取數(shù)據(jù)時(shí),如果從主庫讀取,則可能獲取到最新的數(shù)據(jù);而如果從從庫讀取,則可能獲取到舊的數(shù)據(jù)。這樣也會導(dǎo)致與緩存中的數(shù)據(jù)不一致。

為了解決這些問題 , 可以采用以下幾種方法 :

  • 采用先刪除緩存,再更新數(shù)據(jù)庫方案,在并發(fā)場景下依舊有不一致問題,解決方案是延遲雙刪,但這個(gè)延遲時(shí)間很難評估。
  • 采用先更新數(shù)據(jù)庫,再刪除緩存方案,為了保證兩步都成功執(zhí)行,需配合消息隊(duì)列或訂閱變更日志的方案來做,本質(zhì)是通過重試的方式保證數(shù)據(jù)最終一致性。
  • 采用先更新數(shù)據(jù)庫,再刪除緩存方案,讀寫分離 + 主從庫延遲也會導(dǎo)致緩存和數(shù)據(jù)庫不一致,緩解此問題的方案是延遲雙刪,憑借經(jīng)驗(yàn)發(fā)送延遲消息到隊(duì)列中,延遲刪除緩存,同時(shí)也要控制主從庫延遲,盡可能降低不一致發(fā)生的概率。

總之,根據(jù)場景選擇適合自己的方案

 以上就是Redis與MySQL的雙寫一致性問題的詳細(xì)內(nèi)容,更多關(guān)于Redis與MySQL的一致性的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MySQL刪除表操作實(shí)現(xiàn)(delete、truncate、drop的區(qū)別)

    MySQL刪除表操作實(shí)現(xiàn)(delete、truncate、drop的區(qū)別)

    這篇文章主要介紹了MySQL刪除表操作實(shí)現(xiàn)(delete、truncate、drop的區(qū)別),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • MySQL判斷時(shí)間段是否重合的兩種方法

    MySQL判斷時(shí)間段是否重合的兩種方法

    這篇文章介紹了MySQL判斷時(shí)間段是否重合的兩種方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • MySql?字符集不同導(dǎo)致?left?join?慢查詢的問題解決

    MySql?字符集不同導(dǎo)致?left?join?慢查詢的問題解決

    當(dāng)兩個(gè)表的字符集不一樣,在使用字符型字段進(jìn)行表連接查詢時(shí),就需要特別注意下查詢耗時(shí)是否符合預(yù)期,本文主要介紹了MySql?字符集不同導(dǎo)致?left?join?慢查詢的問題解決,感興趣的可以了解一下
    2024-05-05
  • Mysql避免重復(fù)插入數(shù)據(jù)的4種方式

    Mysql避免重復(fù)插入數(shù)據(jù)的4種方式

    這篇文章主要介紹了Mysql避免重復(fù)插入數(shù)據(jù)的4種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • mysql 無限級分類實(shí)現(xiàn)思路

    mysql 無限級分類實(shí)現(xiàn)思路

    關(guān)于該問題,暫時(shí)自己還沒有深入研究,在網(wǎng)上找到幾種解決方案,各有優(yōu)缺點(diǎn)。
    2011-08-08
  • MySQL中case?when對NULL值判斷的踩坑記錄

    MySQL中case?when對NULL值判斷的踩坑記錄

    最近在學(xué)習(xí)Hive基礎(chǔ)知識時(shí),遇到了遇到了Case?When?Else?End語法,這篇文章主要給大家介紹了關(guān)于MySQL中case?when對NULL值判斷的踩坑記錄,需要的朋友可以參考下
    2021-12-12
  • MySQL中B樹索引和B+樹索引的區(qū)別詳解

    MySQL中B樹索引和B+樹索引的區(qū)別詳解

    這篇文章主要為大家詳細(xì)介紹了MySQL中B樹索引和B+樹索引的區(qū)別,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • MySQL?原理優(yōu)化之Group?By的優(yōu)化技巧

    MySQL?原理優(yōu)化之Group?By的優(yōu)化技巧

    這篇文章主要介紹了MySQL?原理優(yōu)化之Group?By的優(yōu)化技巧,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08
  • MySQL中查詢和展示LONGBLOB類型數(shù)據(jù)的技巧總結(jié)

    MySQL中查詢和展示LONGBLOB類型數(shù)據(jù)的技巧總結(jié)

    在MySQL中LONGBLOB是一種二進(jìn)制大對象(BLOB)數(shù)據(jù)類型,用于存儲大量的二進(jìn)制數(shù)據(jù),這篇文章主要介紹了MySQL中查詢和展示LONGBLOB類型數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下
    2025-08-08
  • MySQL 5.7.27下載安裝配置的詳細(xì)教程

    MySQL 5.7.27下載安裝配置的詳細(xì)教程

    這篇文章主要介紹了MySQL 5.7.27詳細(xì)下載安裝配置教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08

最新評論