seo技術(shù)分享免費(fèi)咨詢北京seo優(yōu)化方案
03——緩存雙寫一致性
一、緩存雙寫一致性
- 如果redis中有數(shù)據(jù),需要和數(shù)據(jù)庫中的值相同
- 如果redis中無數(shù)據(jù),數(shù)據(jù)庫中的值要是最新值,且準(zhǔn)備回寫redis
緩存按照操作來分,可以分為兩種:
-
只讀緩存
-
讀寫緩存
-
同步直寫操作(及時(shí)生效)
寫數(shù)據(jù)庫后,也同步寫redis緩存,緩存和數(shù)據(jù)庫中的數(shù)據(jù)一致
對(duì)于讀寫緩存來說,要想保證緩存和數(shù)據(jù)庫中的數(shù)據(jù)一致,就要采用同步直寫策略
-
異步緩寫策略
正常業(yè)務(wù)中,mysql數(shù)據(jù)變動(dòng)了,但是可以在業(yè)務(wù)上允許出現(xiàn)一定時(shí)間后才作用與redis(倉庫、物流)
異常情況出現(xiàn)了,不得不將失敗的動(dòng)作重新修補(bǔ),有可能需要借助kafka或者其他MQ等消息中間件,實(shí)現(xiàn)重試重寫
-
雙檢加鎖策略:當(dāng)多個(gè)線程同時(shí)去查詢數(shù)據(jù)庫的某一條數(shù)據(jù)時(shí),可以在第一個(gè)查詢數(shù)據(jù)的請(qǐng)求上使用一個(gè)互斥鎖。其他線程獲取鎖失敗,就會(huì)阻塞。第一個(gè)線程查詢完畢,并將數(shù)據(jù)回寫redis后,其他線程直接從redis中獲取數(shù)據(jù)。以此來減輕數(shù)據(jù)庫的壓力。
二、數(shù)據(jù)庫和緩存一致性的幾種更新策略
目標(biāo):數(shù)據(jù)最終一致性
給緩存設(shè)置過期時(shí)間,定期清理緩存并回寫,是保證最終一致性的解決方案。
我們可以對(duì)存入緩存的數(shù)據(jù)設(shè)置過期時(shí)間,所有的寫操作以數(shù)據(jù)庫為準(zhǔn),對(duì)緩存操作只是盡最大努力即可。也就是說如果數(shù)據(jù)庫寫成功,緩存更新失敗,那么只要到達(dá)過期時(shí)間,則后面的讀請(qǐng)求自然會(huì)從數(shù)據(jù)庫中讀取新值然后回填緩存,達(dá)到一致性,切記,要以mysql的數(shù)據(jù)庫寫入庫為準(zhǔn)。
上述方案和后續(xù)落地案例是調(diào)研后的主流+成熟的做法,但是考慮到各個(gè)公司業(yè)務(wù)系統(tǒng)的差距,不是100%絕對(duì)正確,不保證絕對(duì)適配全部情況,請(qǐng)同學(xué)們自行酌情選擇打法,合適自己的最好。
可以停機(jī)的情況:
掛牌報(bào)錯(cuò),凌晨升級(jí),溫馨提示,服務(wù)降級(jí)
單線程,這樣重量級(jí)的數(shù)據(jù)操作最好不要多線程
四種更新策略:
-
先更新數(shù)據(jù)庫,再更新緩存
案例一:
更新mysql的某商品的庫存,當(dāng)前商品的庫存是100,更新為99個(gè)。
1、先更新mysql修改為99成功,然后更新redis。
2、此時(shí)假設(shè)異常出現(xiàn),更新redis失敗了,這導(dǎo)致mysql里面的庫存是99而redis里面的還是100。上述發(fā)生,會(huì)讓數(shù)據(jù)庫里面和緩存redis里面數(shù)據(jù)不一致,讀到redis臟數(shù)據(jù)
案例二:
-
先更新緩存,再更新數(shù)據(jù)庫
業(yè)務(wù)上一般把mysql作為底單數(shù)據(jù)庫,保證最后解釋
案例一:
-
先刪除緩存,再更新數(shù)據(jù)庫
案例:
兩個(gè)并發(fā)操作,一個(gè)是更新操作,另一個(gè)是查詢操作,
A刪除緩存后,B查詢操作沒有命中緩存,B先把老數(shù)據(jù)讀出來后放到緩存中,然后A更新操作更新了數(shù)據(jù)庫。
于是,在緩存中的數(shù)據(jù)還是老的數(shù)據(jù),導(dǎo)致緩存中的數(shù)據(jù)是臟的,而且還一直這樣臟下去了。[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-eSCPx6nt-1692427619711)(https://you-blog.oss-accelerate.aliyuncs.com/2023/202303062316864.png)]
解決方案: 延時(shí)雙刪策略
加上sleep的這段時(shí)間,就是為了讓線程B能夠先從數(shù)據(jù)庫讀取數(shù)據(jù),再把缺失的數(shù)據(jù)寫入緩存,然后,線程A再進(jìn)行刪除。所以,線程A sleep的時(shí)間,就需要大于線程B讀取數(shù)據(jù)再寫入緩存的時(shí)間。這樣一來,其它線程讀取數(shù)據(jù)時(shí),會(huì)發(fā)現(xiàn)緩存缺失,所以會(huì)從數(shù)據(jù)庫中讀取最新值。因?yàn)檫@個(gè)方案會(huì)在第一次刪除緩存值后,延遲一段時(shí)間再次進(jìn)行刪除,所以我們也把它叫做“延遲雙刪”。
延遲雙刪問題:
-
這個(gè)刪除該休眠多久呢
線程A sleep的時(shí)間,需要大于線程B讀取數(shù)據(jù)再寫入緩存的時(shí)間
確認(rèn)時(shí)間的方法:
-
第一種方法:
在業(yè)務(wù)程序運(yùn)行的時(shí)候,統(tǒng)計(jì)下線程讀數(shù)據(jù)和寫緩存的操作時(shí)間,自行評(píng)估自己的項(xiàng)目的讀數(shù)據(jù)業(yè)務(wù)邏輯的耗時(shí),以此為基礎(chǔ)來進(jìn)行估算。然后寫數(shù)據(jù)的休眠時(shí)間則在讀數(shù)據(jù)業(yè)務(wù)邏輯的耗時(shí)基礎(chǔ)上加百毫秒即可。這么做的目的,就是確保讀請(qǐng)求結(jié)束,寫請(qǐng)求可以刪除讀請(qǐng)求造成的緩存臟數(shù)據(jù)。
-
第二種方法:
新啟動(dòng)一個(gè)后臺(tái)監(jiān)控程序,比如后面要講解的VatchDog監(jiān)控程序,會(huì)加時(shí)
-
-
這種同步淘汰策略,吞吐量降低怎么辦
使用異步線程,避免阻塞
-
看門狗WatchDog分析
-
-
先更新數(shù)據(jù)庫,再刪除緩存
-
異常問題:
-
業(yè)務(wù)指導(dǎo)思想
-
微軟云
https://learn.microsoft.com/en-us/azure/architecture/patterns/cache-aside
-
阿里canal
-
-
解決方案
流程如下圖所示:
-
更新數(shù)據(jù)庫數(shù)據(jù)
-
數(shù)據(jù)庫會(huì)將操作信息寫入binlog日志當(dāng)中
-
訂閱程序提取出所需要的數(shù)據(jù)以及key
-
另起一段非業(yè)務(wù)代碼,獲得該信息
-
嘗試刪除緩存操作,發(fā)現(xiàn)刪除失敗
-
將這些信息發(fā)送至消息隊(duì)列
-
重新從消息隊(duì)列中獲得該數(shù)據(jù),重試操作。
-
可以把要?jiǎng)h除的緩存值或者是要更新的數(shù)據(jù)庫值暫存到消息隊(duì)列中(例如使用Kafka/RabbitMQ等)
-
當(dāng)程序沒有能夠成功地刪除緩存值或者是更新數(shù)據(jù)庫值時(shí),可以從消息隊(duì)列中重新讀取這些值,然后再次進(jìn)行刪除或更新。
-
如果能夠成功地刪除或更新,我們就要把這些值從消息隊(duì)列中去除,以免重復(fù)操作,此時(shí),我們也可以保證數(shù)據(jù)庫和緩存的數(shù)據(jù)一致了,否則還需要再次進(jìn)行重試
-
如果重試超過的一定次數(shù)后還是沒有成功,我們就需要向業(yè)務(wù)層發(fā)送報(bào)錯(cuò)信息了,通知運(yùn)維人員。
-
-
類似經(jīng)典的分布式事務(wù)問題
只能保證最終一致性
-
三、總結(jié)
-
如何選擇方案?利弊如何
在大多數(shù)業(yè)務(wù)場(chǎng)景下,優(yōu)先使用先更新數(shù)據(jù)庫,再刪除緩存的方案(先更庫→后刪緩存)。
理由如下:
-
先刪除緩存值再更新數(shù)據(jù)庫,有可能導(dǎo)致請(qǐng)求因緩存缺失而訪問數(shù)據(jù)庫,給數(shù)據(jù)庫帶來壓力導(dǎo)致打滿nysql。.
-
如果業(yè)務(wù)應(yīng)用中讀取數(shù)據(jù)庫和寫緩存的時(shí)間不好估算,那么,延遲雙刪中的等待時(shí)間就不好設(shè)置。
如果使用先更新數(shù)據(jù)庫,再刪除緩存的方案: 如果業(yè)務(wù)層要求必須讀取一致性的數(shù)據(jù),那么我們就需要在更新數(shù)據(jù)庫時(shí),先在Rdis緩存客戶端暫停并發(fā)讀請(qǐng)求,等數(shù)據(jù)庫更新完、緩存值刪除后,再讀取數(shù)據(jù),從而保證數(shù)據(jù)一致性,這是理論可以達(dá)到的效果,但實(shí)際,不推薦,因?yàn)檎鎸?shí)生產(chǎn)環(huán)境中,分布式下很難做到實(shí)時(shí)一致性,一般都是最終一致性。
-
-
總結(jié)