數(shù)據(jù)一致性保障

緩存和數(shù)據(jù)庫(kù)的同步可以通過(guò)以下幾種方式:

  1. 先更新緩存,再更新數(shù)據(jù)庫(kù)
  2. 先更新數(shù)據(jù)庫(kù)存,再更新緩存
  3. 先刪除緩存,再更新數(shù)據(jù)庫(kù),后續(xù)等查詢(xún)把數(shù)據(jù)庫(kù)的數(shù)據(jù)回種到緩存中
  4. 先更新數(shù)據(jù)庫(kù),再刪除緩存,后續(xù)等查詢(xún)把數(shù)據(jù)庫(kù)的數(shù)據(jù)回種到緩存中
  5. 緩存雙刪策略。更新數(shù)據(jù)庫(kù)之前,刪除一次緩存;更新完數(shù)據(jù)庫(kù)后,再進(jìn)行一次延遲刪除
  6. 使用 Binlog 異步更新緩存,監(jiān)聽(tīng)數(shù)據(jù)庫(kù)的 Binlog 變化,通過(guò)異步方式更新 Redis 緩存

以上就是實(shí)現(xiàn)數(shù)據(jù)庫(kù)與緩存一致性的六種方式,這里前面三種都不太推薦使用,后面三種的話(huà)其主要根據(jù)實(shí)際場(chǎng)景:

  • 如果是要考慮實(shí)時(shí)一致性的話(huà),先寫(xiě) MySQL,再刪除 Redis 應(yīng)該是較為優(yōu)的方案,雖然短期內(nèi)數(shù)據(jù)可能不一致,不過(guò)其能盡量保證數(shù)據(jù)的一致性。
  • 如果考慮最終一致性的話(huà),推薦的是使用 binlog + 消息隊(duì)列的方式,這個(gè)方案其有重試和順序消費(fèi),能夠最大限度地保證緩存與數(shù)據(jù)庫(kù)的最終一致性。

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

image.png

由于網(wǎng)絡(luò)原因,請(qǐng)求順序無(wú)法保證,可能出現(xiàn)先更新緩存的請(qǐng)求,后更新數(shù)據(jù)庫(kù),而后更新緩存的請(qǐng)求反而先更新了數(shù)據(jù)庫(kù),這樣就出現(xiàn)了緩存數(shù)據(jù)為 20,數(shù)據(jù)庫(kù)數(shù)據(jù)為 10,即數(shù)據(jù)不一致的情況。

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

image.png

這個(gè)問(wèn)題上面其實(shí)一樣,都是因?yàn)椴l(fā)和網(wǎng)絡(luò)問(wèn)題導(dǎo)致的數(shù)據(jù)庫(kù)與緩存不一致。

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

image.png

盤(pán)一下流程:

  1. 請(qǐng)求 A 先對(duì)緩存中的數(shù)據(jù)進(jìn)行刪除操作。
  2. 請(qǐng)求 B 這個(gè)時(shí)候來(lái)執(zhí)行查詢(xún),發(fā)現(xiàn)緩存中數(shù)據(jù)為空,就去數(shù)據(jù)庫(kù)進(jìn)行查詢(xún)并回寫(xiě)緩存。
  3. 這個(gè)時(shí)候請(qǐng)求 A 刪除緩存中的數(shù)據(jù)之后,進(jìn)行數(shù)據(jù)庫(kù)數(shù)據(jù)的更新。
  4. 但此時(shí)請(qǐng)求 B 已經(jīng)把從數(shù)據(jù)庫(kù)查詢(xún)到的原始數(shù)據(jù)回寫(xiě)緩存了,這個(gè)時(shí)候就出現(xiàn)了上圖的情況,數(shù)據(jù)庫(kù)中查詢(xún)的值是 20,而緩存中的數(shù)據(jù)是 10 。
    讀操作獲取到的數(shù)據(jù)是過(guò)時(shí)的數(shù)據(jù),雖然寫(xiě)操作已經(jīng)完成了,但是因?yàn)榫彺姹粍h除了,讀操作就必須從數(shù)據(jù)庫(kù)中讀取到舊值,并不是最新的數(shù)據(jù)。

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

image.png

先把數(shù)據(jù)庫(kù)的信息修改了,然后再刪除對(duì)應(yīng)的緩存,然后在修改數(shù)據(jù)庫(kù)期間,可以允許一定時(shí)間的緩存不一致,保證緩存的最終一致性。
不過(guò)這種模型也有一定的問(wèn)題,如下圖所示:


image.png

其主要原因在于有一個(gè)寫(xiě)操作,此時(shí)剛好緩存失效,又在同一時(shí)刻剛好有一個(gè)并發(fā)讀請(qǐng)求過(guò)來(lái),且回寫(xiě)緩存的請(qǐng)求晚于緩存刪除,導(dǎo)致數(shù)據(jù)庫(kù)與緩存的不一致。
從上面的表述可以知道,這個(gè)發(fā)生的概率比較低,一般而言業(yè)務(wù)上都會(huì)使用這個(gè)方案。

緩存雙刪(先刪除緩存,再更新數(shù)據(jù)庫(kù),過(guò)段時(shí)間再刪除緩存)

image.png

這個(gè)方案為了避免舊數(shù)據(jù)被回種,等待一段時(shí)間后再延遲刪除緩存。
也可以使用消息隊(duì)列、定時(shí)任務(wù)或者延遲任務(wù)等方式去實(shí)現(xiàn)延遲刪除:


image.png

先寫(xiě)數(shù)據(jù)庫(kù),再通過(guò)Binlog異步更新緩存

image.png

先修改數(shù)據(jù)庫(kù),然后通過(guò) Canal 監(jiān)聽(tīng)數(shù)據(jù)庫(kù)的 binlog 日志,記錄數(shù)據(jù)庫(kù)的修改信息,然后通過(guò)消息隊(duì)列異步修改緩存的數(shù)據(jù)。
這里需要注意需要保證順序消費(fèi),保證緩存中數(shù)據(jù)按順序更新,然后再加上重試機(jī)制,避免因?yàn)榫W(wǎng)絡(luò)問(wèn)題導(dǎo)致更新失敗。

強(qiáng)一致性保障

可以使用分布式讀寫(xiě)鎖實(shí)現(xiàn)強(qiáng)一致性。讀寫(xiě)鎖中讀和讀操作不互斥,讀寫(xiě)互斥,寫(xiě)寫(xiě)互斥。
寫(xiě)操作流程:

  • 獲取寫(xiě)鎖。
  • 更新數(shù)據(jù)庫(kù)。
  • 刪除緩存。
  • 釋放寫(xiě)鎖。

讀操作流程:

  • 獲取讀鎖。
  • 查詢(xún)緩存:如果命中緩存,釋放讀鎖,返回結(jié)果。如果緩存未命中,讀取數(shù)據(jù)庫(kù),并將數(shù)據(jù)更新到緩存。
  • 釋放讀鎖。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容