如何保證Redis與數(shù)據(jù)庫的數(shù)據(jù)一致
ONE 案例
先刪除“緩存”再去更新“數(shù)據(jù)庫”。但是該方案還存在問題:
????????在高并發(fā)情況下,第一個(gè)線程刪除緩存,還沒來得及去操作數(shù)據(jù)庫,這時(shí)第二個(gè)線程訪問緩存,發(fā)現(xiàn)為null,于是去數(shù)據(jù)庫查詢,獲取到需要的值,這時(shí)候第一個(gè)線程才開始操作數(shù)據(jù)庫,然后設(shè)置緩存,但是第二個(gè)線程又跟奇怪的將第一個(gè)線程剛設(shè)置的緩存給覆蓋掉,然后就出現(xiàn)“烏龍”,數(shù)據(jù)不一致的問題也出現(xiàn)了!
解決方案:
① 先操作緩存去修改數(shù)據(jù)庫,但不刪除緩存。將這個(gè)不刪除的緩存設(shè)置為一個(gè)特殊值(*123),當(dāng)客戶端讀緩存的時(shí)候,發(fā)現(xiàn)有前綴包含( * ???),知道他是壞值,就會(huì)進(jìn)行休眠(1秒這樣),然后再去查詢Redis。 //這樣做的弊端是:特殊值對(duì)業(yè)務(wù)可能出現(xiàn)影響,休眠時(shí)間會(huì)重復(fù)(高并發(fā)情況下,修改操作頻繁,反復(fù)會(huì)修改這個(gè)特殊值的內(nèi)容,然后同時(shí)出現(xiàn)睡眠),影響性能。
②延遲雙刪,先刪除緩存數(shù)據(jù),再把數(shù)據(jù)更新到數(shù)據(jù)庫中,休眠一會(huì)(根據(jù)業(yè)務(wù)邏輯的耗時(shí),更改休眠時(shí)間)后再次刪除該緩存數(shù)據(jù)。若線程1是更新請(qǐng)求,線程2是查詢請(qǐng)求,延遲雙刪,可以保證再這兩個(gè)請(qǐng)求同時(shí)存在的情況下的數(shù)據(jù)一致性!確保查詢請(qǐng)求結(jié)束,更新請(qǐng)求可以刪除查詢請(qǐng)求造成的緩存臟數(shù)據(jù)。
總結(jié):寫操作不能太頻繁!
TWO 案例
先刪除“數(shù)據(jù)庫”再去更新“緩存”。
該案例的問題是:數(shù)據(jù)庫寫完之后,再刪除緩存,但刪除失敗了,這會(huì)導(dǎo)致數(shù)據(jù)不一致。
解決方案:
①給緩存設(shè)置一個(gè)過期時(shí)間,但缺點(diǎn)是,過期時(shí)間內(nèi) 不能保證數(shù)據(jù)是有用的數(shù)據(jù),可能是上次沒刪掉的壞數(shù)據(jù)。
②引入MQ,保證原子操作。
一個(gè)去刪緩存,一個(gè)去操作數(shù)據(jù)庫。MQ若是刪除操作失敗了,啟動(dòng)MQ重試機(jī)制,在重試的這段時(shí)間,緩存數(shù)據(jù)不會(huì)更新。
③將熱點(diǎn)數(shù)據(jù)緩存設(shè)置為永不過期,但是在value當(dāng)中寫入一個(gè)邏輯上的過期時(shí)間,另外起一個(gè)后臺(tái)線程,掃描這些key,對(duì)于已邏輯上過期的緩存,進(jìn)行刪除。
總結(jié):始終只能保證一定時(shí)間內(nèi)的最終一致性。
THREE 案例
Redis和Mysql集群實(shí)現(xiàn)的讀寫分離架構(gòu)
????????如果MySQL采用的是讀寫分離的架構(gòu),主從服務(wù)器之間也會(huì)存在時(shí)間差,也就是A更新操作,刪除緩存,并請(qǐng)求主數(shù)據(jù)庫進(jìn)行數(shù)據(jù)更新,主庫與從庫進(jìn)行同步數(shù)據(jù)的操作,B進(jìn)行查詢操作時(shí),緩存中沒有數(shù)據(jù),就去從庫中讀取數(shù)據(jù),此時(shí)主從數(shù)據(jù)未更新完成,拿到的還是舊數(shù)據(jù)。
解決方法是:查詢數(shù)據(jù)經(jīng)過Redis時(shí),若查詢緩存為空時(shí),強(qiáng)制將其指向主數(shù)據(jù)庫中進(jìn)行查詢。
Four 案例
異步更新緩存(基于訂閱binlog的同步機(jī)制)
MySQL binlog增量訂閱消費(fèi)+消息隊(duì)列+增量數(shù)據(jù)更新到redis
讀Redis:熱數(shù)據(jù)基本都在Redis
寫MySQL:增刪改都是操作MySQL
更新Redis數(shù)據(jù):MySQ的數(shù)據(jù)操作binlog,來更新到Redis Redis更新
①數(shù)據(jù)操作主要分為兩大塊:
一個(gè)是全量(將全部數(shù)據(jù)一次寫入到redis)
一個(gè)是增量(實(shí)時(shí)更新) 這里說的是增量,指的是mysql的update、insert、delate變更數(shù)據(jù)。
②讀取binlog后分析 ,利用消息隊(duì)列,推送更新各臺(tái)的redis緩存數(shù)據(jù)。
這樣一旦MySQL中產(chǎn)生了新的寫入、更新、刪除等操作,就可以把binlog相關(guān)的消息推送至Redis,Redis再根據(jù)binlog中的記錄,對(duì)Redis進(jìn)行更新。
這種機(jī)制,很類似MySQL的主從備份機(jī)制,因?yàn)镸ySQL的主備也是通過binlog來實(shí)現(xiàn)的數(shù)據(jù)一致性。
這里可以結(jié)合使用canal(阿里的一款開源框架),通過該框架可以對(duì)MySQL的binlog進(jìn)行訂閱,而canal正是模仿了mysql的slave數(shù)據(jù)庫的備份請(qǐng)求,使得Redis的數(shù)據(jù)更新達(dá)到了相同的效果。
參考文獻(xiàn)
如何保證Redis與數(shù)據(jù)庫的數(shù)據(jù)一致性_mr.two white的博客-CSDN博客_redis保證數(shù)據(jù)一致性文章來源:http://www.zghlxwxcb.cn/news/detail-633793.html
面試33-如何保證Redis與數(shù)據(jù)庫的數(shù)據(jù)一致_嗶哩嗶哩_bilibili文章來源地址http://www.zghlxwxcb.cn/news/detail-633793.html
到了這里,關(guān)于【4種方案】如何保證Redis與數(shù)據(jù)庫的數(shù)據(jù)一致!的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!