詳解讓MySQL和Redis數(shù)據(jù)保持一致的四種策略
1 前言
先闡明一下 MySQL 和 Redis 的關(guān)系:MySQL 是數(shù)據(jù)庫(kù),用來(lái)持久化數(shù)據(jù),一定程度上保證數(shù)據(jù)的可靠性;Redis 是用來(lái)當(dāng)緩存,用來(lái)提升數(shù)據(jù)訪問(wèn)的性能。
關(guān)于如何保證 MySQL 和 Redis 中的數(shù)據(jù)一致(即緩存一致性問(wèn)題),這是一個(gè)非常經(jīng)典的問(wèn)題。
使用過(guò)緩存的人都應(yīng)該知道,在實(shí)際應(yīng)用場(chǎng)景中,要想實(shí)時(shí)刻保證緩存和數(shù)據(jù)庫(kù)中的數(shù)據(jù)一樣,很難做到。
基本上都是盡可能讓他們的數(shù)據(jù)在絕大部分時(shí)間內(nèi)保持一致,并保證最終是一致的。
1.1 緩存不一致是如何產(chǎn)生的
如果數(shù)據(jù)一直沒(méi)有變更,那么就不會(huì)出現(xiàn)緩存不一致的問(wèn)題。
通常緩存不一致是發(fā)生在數(shù)據(jù)有變更的時(shí)候。因?yàn)槊看螖?shù)據(jù)變更你需要同時(shí)操作數(shù)據(jù)庫(kù)和緩存,而他們又屬于不同的系統(tǒng),無(wú)法做到同時(shí)操作成功或失敗,總會(huì)有一個(gè)時(shí)間差。在并發(fā)讀寫(xiě)的時(shí)候可能就會(huì)出現(xiàn)緩存不一致的問(wèn)題(理論上通過(guò)分布式事務(wù)可以保證這一點(diǎn),不過(guò)實(shí)際上基本上很少有人這么做)。
雖然沒(méi)辦法在數(shù)據(jù)有變更時(shí),保證緩存和數(shù)據(jù)庫(kù)強(qiáng)一致,但對(duì)緩存的更新還是有一定設(shè)計(jì)方法的,遵循這些設(shè)計(jì)方法,能夠讓這個(gè)不一致的影響時(shí)間和影響范圍最小化。
1.2 緩存更新的幾種設(shè)計(jì)
緩存更新的設(shè)計(jì)方法大概有以下四種:
先刪除緩存,再更新數(shù)據(jù)庫(kù)(這種方法在并發(fā)下最容易出現(xiàn)長(zhǎng)時(shí)間的臟數(shù)據(jù),不可?。?/p>
先更新數(shù)據(jù)庫(kù),刪除緩存(Cache Aside Pattern)
只更新緩存,由緩存自己同步更新數(shù)據(jù)庫(kù)(Read/Write Through Pattern)
只更新緩存,由緩存自己異步更新數(shù)據(jù)庫(kù)(Write Behind Cache Pattern)
接下來(lái)詳細(xì)介紹一些這四種設(shè)計(jì)方法
2 設(shè)計(jì)方法一:先刪除緩存,再更新數(shù)據(jù)庫(kù)
這種方法在并發(fā)讀寫(xiě)的情況下容易出現(xiàn)緩存不一致的問(wèn)題
如上圖所示,其可能的執(zhí)行流程順序?yàn)椋?/p>
- 客戶(hù)端1 觸發(fā)更新數(shù)據(jù)A的邏輯
- 客戶(hù)端2 觸發(fā)查詢(xún)數(shù)據(jù)A的邏輯
- 客戶(hù)端1 刪除緩存中數(shù)據(jù)A
- 客戶(hù)端2 查詢(xún)緩存中數(shù)據(jù)A,未命中
- 客戶(hù)端2 從數(shù)據(jù)庫(kù)查詢(xún)數(shù)據(jù)A,并更新到緩存中
- 客戶(hù)端1 更新數(shù)據(jù)庫(kù)中數(shù)據(jù)A
可見(jiàn),最后緩存中的數(shù)據(jù) A 跟數(shù)據(jù)庫(kù)中的數(shù)據(jù) A 是不一致的,緩存中的數(shù)據(jù)A是舊的臟數(shù)據(jù)。
因此一般不建議使用這種方式。
3 設(shè)計(jì)方法二:先更新數(shù)據(jù)庫(kù),再讓緩存失效
這種方法在并發(fā)讀寫(xiě)的情況下,也可能會(huì)出現(xiàn)短暫緩存不一致的問(wèn)題
如上圖所示,其可能執(zhí)行的流程順序?yàn)椋?/p>
- 客戶(hù)端1 觸發(fā)更新數(shù)據(jù)A的邏輯
- 客戶(hù)端2 觸發(fā)查詢(xún)數(shù)據(jù)A的邏輯
- 客戶(hù)端3 觸發(fā)查詢(xún)數(shù)據(jù)A的邏輯
- 客戶(hù)端1 更新數(shù)據(jù)庫(kù)中數(shù)據(jù)A
- 客戶(hù)端2 查詢(xún)緩存中數(shù)據(jù)A,命中返回(舊數(shù)據(jù))
- 客戶(hù)端1 讓緩存中數(shù)據(jù)A失效
- 客戶(hù)端3 查詢(xún)緩存中數(shù)據(jù)A,未命中
- 客戶(hù)端3 查詢(xún)數(shù)據(jù)庫(kù)中數(shù)據(jù)A,并更新到緩存中
可見(jiàn),最后緩存中的數(shù)據(jù)A和數(shù)據(jù)庫(kù)中的數(shù)據(jù) A 是一致的,理論上可能會(huì)出現(xiàn)一小段時(shí)間數(shù)據(jù)不一致,不過(guò)這種概率也比較低,大部分的業(yè)務(wù)也不會(huì)有太大的問(wèn)題。
4 設(shè)計(jì)方法三:只更新緩存,由緩存自己同步更新數(shù)據(jù)庫(kù)(Read/Write Through Pattern)
只更新緩存,由緩存自己同步更新數(shù)據(jù)庫(kù)(Read/Write Through Pattern)
如上圖所示,其可能執(zhí)行的流程順序?yàn)椋?/p>
- 客戶(hù)端1 觸發(fā)更新數(shù)據(jù) A 的邏輯
- 客戶(hù)端2 觸發(fā)查詢(xún)數(shù)據(jù) A 的邏輯
- 客戶(hù)端1 更新緩存中數(shù)據(jù) A,緩存同步更新數(shù)據(jù)庫(kù)中數(shù)據(jù) A,再返回結(jié)果
- 客戶(hù)端2 查詢(xún)緩存中數(shù)據(jù) A,命中返回
Read Through 和 WriteThrough 的流程類(lèi)似,只是在客戶(hù)端查詢(xún)數(shù)據(jù)A時(shí),如果緩存中數(shù)據(jù)A失效了(過(guò)期或被驅(qū)逐淘汰),則緩存會(huì)同步去數(shù)據(jù)庫(kù)中查詢(xún)數(shù)據(jù)A,并緩存起來(lái),再返回給客戶(hù)端。
這種方式緩存不一致的概率極低,只不過(guò)需要對(duì)緩存進(jìn)行專(zhuān)門(mén)的改造。
5 只更新緩存,由緩存自己異步更新數(shù)據(jù)庫(kù)(Write Behind Cache Pattern)
這種方式性詳單于是業(yè)務(wù)只操作更新緩存,再由緩存異步去更新數(shù)據(jù)庫(kù),例如:
如上圖所示,其可能的執(zhí)行流程順序?yàn)椋?/p>
- 客戶(hù)端1 觸發(fā)更新數(shù)據(jù) A 的邏輯
- 客戶(hù)端2 觸發(fā)查詢(xún)數(shù)據(jù) A 的邏輯
- 客戶(hù)端1 更新緩存中的數(shù)據(jù) A,返回
- 客戶(hù)端2 查詢(xún)緩存中的數(shù)據(jù) A,命中返回
- 緩存異步更新數(shù)據(jù) A 到數(shù)據(jù)庫(kù)中
這種方式的優(yōu)勢(shì)是讀寫(xiě)的性能都非常好,基本上只要操作完內(nèi)存后就返回給客戶(hù)端了,但是其是非強(qiáng)一致性,存在丟失數(shù)據(jù)的情況。
如果在緩存異步將數(shù)據(jù)更新到數(shù)據(jù)庫(kù)中時(shí),緩存服務(wù)掛了,此時(shí)未更新到數(shù)據(jù)庫(kù)中的數(shù)據(jù)就丟失了。
6 小結(jié)
上面講到的幾種緩存更新的設(shè)計(jì)方式,都是前人總結(jié)出來(lái)的經(jīng)驗(yàn),這些方式或多或少都有一些弊端,并不完美,實(shí)際上也很難有完美的設(shè)計(jì)。大家在做系統(tǒng)設(shè)計(jì)的時(shí)候,也不要去追求完美,要有一些取舍,找到一種最適合自己業(yè)務(wù)場(chǎng)景的方式就行。
到此這篇關(guān)于讓MySQL和Redis數(shù)據(jù)保持一致的四種策略的文章就介紹到這了,更多相關(guān)MySQL和Redis數(shù)據(jù)保持一致內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql 獲取當(dāng)前日期函數(shù)及時(shí)間格式化參數(shù)詳解
這篇文章主要介紹了mysql 獲取當(dāng)前日期函數(shù)now()及時(shí)間格式化DATE_FROMAT函數(shù)以及參數(shù)詳細(xì)介紹,需要的朋友可以參考下2014-08-08Mysql深入了解聯(lián)表查詢(xún)的特點(diǎn)
這篇文章主要給大家介紹了關(guān)于MySQL聯(lián)表查詢(xún)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07mysql數(shù)據(jù)庫(kù)如何導(dǎo)入導(dǎo)出sql文件
這篇文章主要介紹了mysql數(shù)據(jù)庫(kù)如何導(dǎo)入導(dǎo)出sql文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11詳解MySQL查看執(zhí)行慢的SQL語(yǔ)句(慢查詢(xún))
查看執(zhí)行慢的SQL語(yǔ)句,需要先開(kāi)啟慢查詢(xún)?nèi)罩?,MySQL的慢查詢(xún)?nèi)罩?,記錄在MySQL中響應(yīng)時(shí)間超過(guò)閥值的語(yǔ)句(具體指運(yùn)行時(shí)間超過(guò)long_query_time值的SQL,本文給大家介紹MySQL查看執(zhí)行慢的SQL語(yǔ)句,感興趣的朋友跟隨小編一起看看吧2024-03-03MySQL主從配置及haproxy和keepalived搭建過(guò)程解析
這篇文章主要介紹了MySQL主從配置及haproxy和keepalived搭建,本次運(yùn)行環(huán)境是在docker中,也會(huì)介紹一些docker的知識(shí),需要的朋友可以參考下2022-05-05mysql 8.0 錯(cuò)誤The server requested authentication method unkno
在本篇文章里小編給大家整理的是關(guān)于mysql 8.0 錯(cuò)誤The server requested authentication method unknown to the client解決方法,有此需要的朋友們可以學(xué)習(xí)下。2019-08-08使用Canal監(jiān)聽(tīng)MySQL Binlog日志的實(shí)現(xiàn)方案
本文檔探討了在分布式系統(tǒng)中處理超時(shí)未支付訂單的挑戰(zhàn)與解決方案,文檔還詳細(xì)介紹了MySQL Binlog的配置、Canal中間件的部署與配置,以及消息監(jiān)聽(tīng)處理的實(shí)現(xiàn),確保了方案的可操作性,需要的朋友可以參考下2024-12-12MySQL如何給查詢(xún)結(jié)果添加行號(hào)
這篇文章主要介紹了MySQL如何給查詢(xún)結(jié)果添加行號(hào)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07