濮阳杆衣贸易有限公司

主頁 > 知識庫 > MySQL與Redis如何保證數(shù)據(jù)一致性詳解

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

熱門標簽:hbuilder地圖標注 400電話申請怎么看 隨州營銷電話機器人怎么樣 機器人電話機創(chuàng)意繪畫 杭州400電話如何申請的 高德地圖標注商家在哪 天音通信電話機器人 江西南昌百應電話機器人 400電話從哪里申請濱州

前言

由于緩存的高并發(fā)和高性能已經(jīng)在各種項目中被廣泛使用,在讀取緩存這方面基本都是一致的,大概都是按照下圖的流程進行操作:

但是在更新緩存方面,是更新完數(shù)據(jù)庫再更新緩存還是直接刪除緩存呢?又或者是先刪除緩存再更新數(shù)據(jù)庫?在這一點上就值得探討了。

一致性方案

在實際項目開發(fā)中需要保證數(shù)據(jù)庫和緩存中的數(shù)據(jù)一致,否則人家充值了100塊,不斷刷新卻還是顯示0.01元,豈不是尷尬?從理論上來說,為緩存設(shè)置過期時間是最終保證數(shù)據(jù)一致性的解決方案,采用這種方案的話,所有的寫操作都是以數(shù)據(jù)庫為準,如果數(shù)據(jù)庫寫入成功但是緩存更新失敗,只要緩存到過期時間之后后面讀緩存時自然會在數(shù)據(jù)庫中讀取新的值然后更新緩存。接下來探討的思路主要的方向是在不依賴為緩存設(shè)置過期時間的前提下如何保證數(shù)據(jù)一致性。這里主要探討三種方案:

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

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

這種方案是普遍被反對的(在我的認知范圍中~),為啥呢?為啥這種方案就被反對呢?原因主要有兩方面,請聽我細細道來:

首先從數(shù)據(jù)安全方面考慮,如果同時有請求A和請求B同時進行操作,A先更新了數(shù)據(jù)庫的一條數(shù)據(jù),隨后B馬上有更新了該條數(shù)據(jù),但是可能因為網(wǎng)絡(luò)延遲等原因,B卻比A先更新了緩存,就會出現(xiàn)一種什么情況呢?緩存中的數(shù)據(jù)并不最新的B更新過的數(shù)據(jù),就導致了數(shù)據(jù)不一致的情況。

其次從業(yè)務場景方面考慮,如果是一個寫數(shù)據(jù)庫較多而讀數(shù)據(jù)庫較少的業(yè)務,如果采用這種方案就會導致數(shù)據(jù)還沒讀緩存就會被頻繁更新,白白浪費性能。

綜合以上兩方面的考慮,這種方案果斷pass。下面的兩種方案就是爭議較大的兩種方案了,到底是先刪緩存再更新數(shù)據(jù)庫還是先更新數(shù)據(jù)庫再刪除緩存?

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

如果同時有一個請求A進行更新操作,請求B進行查詢操作,就可能會出現(xiàn)A請求進行寫操作前會刪除緩存,B請求剛好此時進來發(fā)現(xiàn)緩存是空的,B請求就會查詢數(shù)據(jù)庫,如果此時A請求的寫操作還未完成,B請求查詢到的就還是舊的值,還是會將舊的值寫入緩存,A請求將新的值寫入數(shù)據(jù)庫,此時就會導致數(shù)據(jù)不一致的問題,如果不采用給緩存設(shè)置過期時間的策略,該數(shù)據(jù)永遠都是臟數(shù)據(jù)。

解決這種情況可以采用延時雙刪的策略,就是在更新數(shù)據(jù)庫之前先刪除緩存,然后對數(shù)據(jù)庫進行寫入操作,數(shù)據(jù)庫更新完成之后再次進行刪除緩存的操作,目的是刪除讀請求可能造成的緩存臟數(shù)據(jù),第二次刪除緩存之前可以休眠幾秒,具體時間開發(fā)者可以評估一下自己項目讀數(shù)據(jù)業(yè)務邏輯的耗時,然后在該耗時基礎(chǔ)上加幾百ms即可,這么做的目的就是確保讀請求結(jié)束寫請求可以刪除讀請求造成的臟數(shù)據(jù)。如果MySQL采用的是讀寫分離的架構(gòu),可能由于主從延時的原因造成數(shù)據(jù)不一致,可以在寫操作完成之后根據(jù)主從延時時間休眠一下然后再進行刪除緩存的操作。延時雙刪的偽代碼如下:

# 偽代碼
def delay_delete():
    redis.delete('name')  # 更新數(shù)據(jù)庫之前先刪除緩存
    sql = 'update info set name='lili' where id=1;'  # 更新數(shù)據(jù)庫
    cursor.execute(sql)  
    time.sleep(1)  # 如果mysql是主從架構(gòu)則休眠主從延時的時間再多幾百ms
    redis.delete('name')  # 再次刪除緩存

那會不會存在第二次刪除緩存失敗的情況呢?如果第二次刪除失敗,還是會造成緩存和數(shù)據(jù)庫不一致的問題,又如何解決呢?且看下一種方案。

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

老外提出了一個緩存更新方案Cache−AsidepatternCache-Aside patternCache−Asidepattern,文章中提到**應用程序應該從cache中獲取數(shù)據(jù),如果獲取成功直接返回,如果沒有獲取成功,則從數(shù)據(jù)庫中獲取,成功后放到緩存中,更新數(shù)據(jù)時應該先把數(shù)據(jù)存到數(shù)據(jù)庫中成功后再讓緩存失效。**原文如下

If an application updates information, it can follow the write-through strategy by making the modification to the data store, and by invalidating the corresponding item in the cache.
When the item is next required, using the cache-aside strategy will cause the updated data to be retrieved from the data store and added back into the cache.

這種方案會不會產(chǎn)生數(shù)據(jù)不一致的情況呢?比如下述這種情況:

有兩個請求A和B,A進行查詢同時B進行更新,假設(shè)發(fā)生下述情況:

①此時緩存剛好失效

②請求A 就會去查詢數(shù)據(jù)庫得到一個舊的值

③請求B將新的值寫入數(shù)據(jù)庫

④請求B寫入成功后刪除緩存

⑤請求A將查到的機制寫入緩存,產(chǎn)生臟數(shù)據(jù)...

如果發(fā)聲上述情況,確實會產(chǎn)生數(shù)據(jù)不一致的情況,但是XDM想一想,發(fā)生這種情況的概率是多少呢?如果先要產(chǎn)生這種結(jié)果,就必須有一個條件,就是請求B的操作時間非常短,短到什么程度呢,就是請求B寫入數(shù)據(jù)庫的操作要比請求A從數(shù)據(jù)庫中讀取數(shù)據(jù)的速度要快(因為redis非???,因此操作redis的時間可以暫且忽略),只有這種情況下④才可能比⑤先發(fā)聲,但是數(shù)據(jù)庫的讀操作要遠比寫操作快的多,不然做讀寫分離干嘛呢?所以這種情況發(fā)生的概率是非常非常非常的低,但是如果強迫癥患者出現(xiàn)必須要解決怎么辦呢?就可以采用給緩存設(shè)置過期時間或者采用第二種方案的延時雙刪策略,保證讀請求完成之后在進行刪除操作。

最后的問題

還有問題呀,就是最終解決方案三可能 出現(xiàn)的極低概率的數(shù)據(jù)不一致的方案是采用方案二的延時雙刪策略,可是在方案二中也說了,如果出現(xiàn)緩存刪除失敗的情況咋辦?那不是還會出現(xiàn)數(shù)據(jù)不一致的問題嗎?這個問題到底如何解決呢?這里提供一個重試機制,刪除失敗就重試一次唄,這里提供一種重試的方案。

①更新數(shù)據(jù)庫
②由于各種原因緩存刪除失敗
③將刪除失敗的緩存放入消息隊列中
④業(yè)務代碼從消息隊列中獲取需要刪除的key
⑤繼續(xù)嘗試刪除操作,直到成功

總結(jié)

到此這篇關(guān)于MySQL與Redis如何保證數(shù)據(jù)一致性的文章就介紹到這了,更多相關(guān)MySQL與Redis數(shù)據(jù)一致性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Redis緩存常用4種策略原理詳解
  • 聊一聊Redis與MySQL雙寫一致性如何保證
  • 詳解redis緩存與數(shù)據(jù)庫一致性問題解決
  • redis實現(xiàn)分布式的方法總結(jié)
  • 面試常問:如何保證Redis緩存和數(shù)據(jù)庫的數(shù)據(jù)一致性

標簽:葫蘆島 保定 招商 昆明 鶴崗 常德 沈陽 石嘴山

巨人網(wǎng)絡(luò)通訊聲明:本文標題《MySQL與Redis如何保證數(shù)據(jù)一致性詳解》,本文關(guān)鍵詞  MySQL,與,Redis,如何,保證,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《MySQL與Redis如何保證數(shù)據(jù)一致性詳解》相關(guān)的同類信息!
  • 本頁收集關(guān)于MySQL與Redis如何保證數(shù)據(jù)一致性詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    玉田县| 江阴市| 从江县| 济源市| 贞丰县| 阿克苏市| 曲水县| 修武县| 高平市| 五寨县| 横山县| 石泉县| 南平市| 东宁县| 新丰县| 镇宁| 高要市| 容城县| 上高县| 巩留县| 杨浦区| 双峰县| 鹤庆县| 磐安县| 海丰县| 永靖县| 中西区| 铁岭县| 长宁县| 渝北区| 内江市| 万载县| 泰和县| 乾安县| 什邡市| 江川县| 明光市| 泸州市| 蛟河市| 苍溪县| 凤冈县|