自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL 與 Redis 緩存一致性的實現(xiàn)與挑戰(zhàn)

數(shù)據(jù)庫
在許多應(yīng)用中,常常將 Redis 用作緩存層,以加速對數(shù)據(jù)的訪問。然而,在使用 MySQL 和 Redis 組合時,保持緩存與數(shù)據(jù)庫之間的一致性是一個不得不考慮的問題。

緩存是提高應(yīng)用性能的重要手段之一,而 MySQL 和 Redis 是兩種常用的數(shù)據(jù)存儲和緩存技術(shù)。在許多應(yīng)用中,常常將 Redis 用作緩存層,以加速對數(shù)據(jù)的訪問。然而,在使用 MySQL 和 Redis 組合時,保持緩存與數(shù)據(jù)庫之間的一致性是一個不得不考慮的問題。

一、緩存一致性的挑戰(zhàn)

MySQL 和 Redis 之間的緩存一致性涉及到兩個方面:

1.數(shù)據(jù)一致性

數(shù)據(jù)在 MySQL 和 Redis 中的一致性是指在對數(shù)據(jù)進(jìn)行更新操作時,確保MySQL 和 Redis 中的數(shù)據(jù)保持同步。如果 Redis 中的緩存數(shù)據(jù)與 MySQL 數(shù)據(jù)庫中的數(shù)據(jù)不一致,可能會導(dǎo)致應(yīng)用程序出現(xiàn)錯誤以及一些未知的問題。

2.緩存有效性

緩存有效性是指 Redis 中的緩存數(shù)據(jù)是否仍然有效,是否需要更新或者過期。如果 Redis 中的緩存數(shù)據(jù)過期,但 MySQL 中的數(shù)據(jù)已經(jīng)更新,可能會導(dǎo)致從 Redis 中獲取到的數(shù)據(jù)不準(zhǔn)確。

再說實現(xiàn)緩存與數(shù)據(jù)庫數(shù)據(jù)一致性的實現(xiàn)方法之前,我們先來了解一下什么是緩存模式?

直接往下看也可以,我在這篇文章里面會重新對幾種緩存模式進(jìn)行一下介紹,并加以配圖說明。

二、緩存模式有哪些

如果你讀過上面緩存模式那篇文章的話,相信你對緩存模式應(yīng)該有一定的了解了,如果不了解也沒關(guān)系,我們一起來看看吧。

1.Cache Aside

最常用的緩存模式,大體意思是先從 cache 中取數(shù)據(jù),沒有獲取到則從數(shù)據(jù)庫中讀取,成功后放到緩存中;

如果在 cache 中獲取到數(shù)據(jù)直接返回;

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

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

遇到的問題是兩個并發(fā)的更新操作,數(shù)據(jù)庫先更新的后更新緩存,數(shù)據(jù)庫后更新的先更新緩存,這樣就會造成數(shù)據(jù)庫與緩存的數(shù)據(jù)不一致,應(yīng)用程序中讀取的數(shù)據(jù)都是臟數(shù)據(jù)

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

遇到的問題是有兩個并發(fā)操作,一個更新操作先刪除了緩存,此時另一個并發(fā)的讀取操作沒有命中緩存,直接讀取數(shù)據(jù)庫并更新回了緩存,這個時候正好更新操作完成數(shù)據(jù)更新。此時數(shù)據(jù)庫和緩存的數(shù)據(jù)不一致,應(yīng)用程序讀取的數(shù)據(jù)都臟數(shù)據(jù)了

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

這個方式也算是我們實際系統(tǒng)使用中比較推薦的一種方式,但是這種方式在理論上還是可能會出現(xiàn)問題,兩個并發(fā)操作,其中一個查詢操作沒有命中緩存,此時查詢出來了數(shù)據(jù)庫中的老數(shù)據(jù),此時另一個并發(fā)的更新操作,在剛才的并發(fā)讀操作之后更新了數(shù)據(jù)庫中的數(shù)據(jù)并刪除了緩存,然后并發(fā)讀操作線程又把老數(shù)據(jù)寫入了緩存,此時又造成了數(shù)據(jù)的不一致,應(yīng)用程序讀取的都是臟數(shù)據(jù)。因為這種概率差生的情況實在是太小,所以才是我們系統(tǒng)中經(jīng)常使用的一種方式了。

2.Read/Write Through

Cache Aside 模式中,應(yīng)用程序需要維護(hù)兩個數(shù)據(jù)存儲,一個是緩存,一個是數(shù)據(jù)庫,在 Read/Write Through 更新模式中,應(yīng)用程序只需要維護(hù)緩存,數(shù)據(jù)庫的維護(hù)工作就有緩存代理了

(1) Read Through

Read Through 模式就是在查詢時更新緩存,也就是說,在緩存失效時,Cache Aside 模式是由調(diào)用方負(fù)責(zé)把數(shù)據(jù)載入緩存,而 Read Through 模式是緩存服務(wù)自己更新緩存,自己來加載數(shù)據(jù)。

當(dāng)應(yīng)用程序執(zhí)行讀操作時,如果緩存中不存在所需數(shù)據(jù),則緩存會自動從數(shù)據(jù)源(如數(shù)據(jù)庫)中讀取數(shù)據(jù),并將數(shù)據(jù)加載到緩存中,然后返回給應(yīng)用程序。

Read-Through 策略減少了應(yīng)用程序與數(shù)據(jù)源之間的直接交互次數(shù),提高了讀操作的性能和響應(yīng)速度。

(2) Write Through

Write Through 和 Read Through 類似,當(dāng)數(shù)據(jù)更新時,如果命中緩存則更新緩存,然后緩存更新數(shù)據(jù)庫,這是一個同步的操作;如果沒有命中緩存,直接更新數(shù)據(jù)庫返回。

Write-Through 策略保證了緩存和數(shù)據(jù)源中的數(shù)據(jù)一致性,但由于每次寫操作都需要等待數(shù)據(jù)源的確認(rèn),可能會影響寫操作的性能和延遲。

3. Write Behind Caching

Write Behind Caching 更新模式是在更新數(shù)據(jù)時只更新緩存,不更新數(shù)據(jù)庫,而我們的緩存會異步的更新數(shù)據(jù)庫。這個模式的話就是速度快,畢竟我們直接操作內(nèi)存,因為是異步的,Write Behind Caching 更新模式還可以合并對同一個數(shù)據(jù)的多次操作到數(shù)據(jù)庫,所以性能的提升也是很明顯的

問題就是數(shù)據(jù)不是強(qiáng)一致性的,而且還可能會丟失,Write Behind Caching 更新模式實現(xiàn)邏輯復(fù)雜,因為它需要確認(rèn)有哪些數(shù)據(jù)是被更新的,哪些數(shù)據(jù)是需要刷到持久層的數(shù)據(jù)庫的。只有當(dāng)緩存失效的時候才會把它真正的持久化起來。

Write-Behind 策略提高了寫操作的性能和響應(yīng)速度,但在寫入緩存后,數(shù)據(jù)源中的數(shù)據(jù)可能會落后于緩存中的數(shù)據(jù)一段時間,存在一定的數(shù)據(jù)一致性風(fēng)險。

三、一致性有哪些

說到一致性,我們應(yīng)該想到的就是分布式系統(tǒng)中多個節(jié)點(diǎn)對看到的數(shù)據(jù)副本都保持一致的特性。換個說法就是,無論用戶在哪個節(jié)點(diǎn)上執(zhí)行操作,最終所有節(jié)點(diǎn)上的數(shù)據(jù)是相同的,且滿足一定的約束條件。

在分布式系統(tǒng)中,實現(xiàn)一致性是很困難的,因為系統(tǒng)中的多個節(jié)點(diǎn)可能會因為網(wǎng)絡(luò)延遲,節(jié)點(diǎn)故障或者其他的因素導(dǎo)致多個數(shù)據(jù)副本之間的狀態(tài)不一致。為了實現(xiàn)分布式系統(tǒng)中的一致性,業(yè)界常用的算法和協(xié)議有 Paxos、Raft、ZAB。

分布式系統(tǒng)的一致性又分為強(qiáng)一致性、弱一致性、最終一致性。

  • 強(qiáng)一致性:最嚴(yán)格的一致性,相當(dāng)于對于用戶來說是最友好的。因為這個相當(dāng)于系統(tǒng)寫入的是什么數(shù)據(jù),讀取時也就是什么數(shù)據(jù)。
  • 弱一致性:相比于強(qiáng)一致性,弱一致性不承諾立即讀取最新的值,也不承諾多久之后數(shù)據(jù)一致。但是會盡可能的保證在到達(dá)某個時間點(diǎn)之后,數(shù)據(jù)達(dá)到一致狀態(tài)。
  • 最終一致性:最終一致性是弱一致性的一個特例,保證在一定時間之后達(dá)到數(shù)據(jù)一致狀態(tài),因此最終一致性也是目前業(yè)界來說最推崇的模型。

四、一致性實現(xiàn)方法

1.雙寫

雙寫其實就是 Write Through 模式,在寫入 MySQL 數(shù)據(jù)庫的同時,立即寫入 Redis 緩存。這樣可以確保 MySQL 和 Redis 中的數(shù)據(jù)保持一致,但增加了寫入的延遲,并且增加了系統(tǒng)復(fù)雜度。

(1) 雙寫為什么先操作數(shù)據(jù)庫在操作緩存?

我們來看如下的例子,線程A 與 線程B 是一組并發(fā)請求。

  • 線程A 發(fā)起一個寫請求、先刪除 Redis 中的緩存。
  • 線程B 發(fā)起一個讀請求,沒有命中緩存。
  • 線程B 讀取數(shù)據(jù)庫,獲取數(shù)據(jù)。
  • 線程B 寫入老數(shù)據(jù)到緩存。
  • 線程A 寫入DB 新數(shù)據(jù)。

到這就發(fā)現(xiàn)了問題了吧,如果你沒發(fā)現(xiàn),那就跟著我的思路來看一下。

大家來看第三步,線程B 去讀取數(shù)據(jù)庫,此時 線程A 是還沒有寫入新數(shù)據(jù)的,所以此時 線程B 讀取的數(shù)據(jù)是老數(shù)據(jù)。

而第5步,線程A 往數(shù)據(jù)庫寫入的才是最新的數(shù)據(jù)。

所以此時也就造成了數(shù)據(jù)不一致 了。

對于這種情況造成的臟數(shù)據(jù)緩存,有的小伙伴可能就提出來了,可以使用緩存雙刪啊,那么我們來繼續(xù)往下看。

(2) 緩存延遲雙刪

延遲雙刪,就是字面意思,刪除兩邊緩存。你知道問題在哪嗎,想一想?

。。。。。。

雙刪,有可能刪除失敗嗎?

刪除失敗怎么辦?

雙刪的步驟如下:

  • 刪除緩存。
  • 更新數(shù)據(jù)庫。
  • 延遲刪除(此時延遲的差不多是讀請求的耗時多一點(diǎn),防止讀請求設(shè)置臟數(shù)據(jù)緩存)。

(3) 刪除緩存的重試機(jī)制

刪除緩存失敗,第一個想到的應(yīng)該是,刪除失敗了就多刪除幾次吧。

所以我們可以借助于消息隊列,將刪除失敗的 key 加入到消息隊列,對消息進(jìn)行重試刪除操作。

既然我們都用到消息隊列了,那么我們?yōu)槭裁床恢苯颖O(jiān)聽 binlog 實現(xiàn)異步刪除緩存呢。

2.消息隊列

使用消息隊列監(jiān)聽數(shù)據(jù)庫變更事件、異步更新緩存。能夠保證在數(shù)據(jù)庫更新后,緩存能夠按照順序進(jìn)行更新。

此時的例子就是,使用 Canal 監(jiān)聽 binlog ,發(fā)送數(shù)據(jù)到 MQ 中,應(yīng)用程序監(jiān)聽 MQ 消息實現(xiàn) Redis 緩存的更新。

五、總結(jié)

實現(xiàn) MySQL 與 Redis緩存的一致性中,需要考慮很多的方面,最直觀的就是業(yè)務(wù)場景,性能要求,以及數(shù)據(jù)的安全等因素綜合考慮。

例如,對于讀多寫少的場景,可以采用 Read/Write Through 模式;

而對于寫操作頻繁的場景,則可能需要考慮 Write Behind Caching 模式。

責(zé)任編輯:趙寧寧 來源: 醉魚Java
相關(guān)推薦

2024-04-11 13:45:14

Redis數(shù)據(jù)庫緩存

2023-09-24 14:35:43

Redis數(shù)據(jù)庫

2022-12-27 08:56:28

2023-02-17 07:54:39

2020-05-12 10:43:22

Redis緩存數(shù)據(jù)庫

2024-05-08 16:37:17

MySQLRedis數(shù)據(jù)庫

2017-07-25 14:38:56

數(shù)據(jù)庫一致性非鎖定讀一致性鎖定讀

2022-12-14 08:23:30

2023-08-15 09:31:01

分布式緩存

2016-12-19 18:41:09

哈希算法Java數(shù)據(jù)

2021-06-11 09:21:58

緩存數(shù)據(jù)庫Redis

2021-06-22 10:22:08

業(yè)務(wù)IT一致性首席信息官

2020-09-03 09:45:38

緩存數(shù)據(jù)庫分布式

2025-04-27 08:52:21

Redis數(shù)據(jù)庫緩存

2020-06-01 22:09:48

緩存緩存同步緩存誤用

2021-06-04 09:56:12

RedisMySQL美團(tuán)

2024-08-06 09:42:23

2023-07-27 08:29:09

2016-11-16 19:15:34

消息時序分布式系統(tǒng)

2021-04-24 16:58:03

數(shù)據(jù)庫工具技術(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號