更新時間:2022-12-28 16:48:09 來源:動力節(jié)點 瀏覽1252次
首先我們先了解下緩存是什么?
緩存就是把低速存儲的結(jié)果,臨時保存在高速存儲的技術(shù)。
為什么使用redis進(jìn)行緩存數(shù)據(jù)?
Redis嘛,就是一種運行速度很快,并發(fā)很強的跑在內(nèi)存上的NoSql數(shù)據(jù)庫,支持鍵到五種數(shù)據(jù)類型的映射,(string、list、set、zset、hash),而memecache只能支持簡單的數(shù)據(jù)類型。另外redis可以完成一部份數(shù)據(jù)的持久化,而memecache完全將數(shù)據(jù)保存在內(nèi)存中,不進(jìn)行持久化,如果服務(wù)器出問題,數(shù)據(jù)將全部丟失,另外一個原因是redis底層實現(xiàn)優(yōu)化比memecache好。另外采用了多路復(fù)用io阻塞機制,數(shù)據(jù)結(jié)構(gòu)簡單,操作節(jié)省時間。
那常見的保證緩存與數(shù)據(jù)庫一致的方法有哪些呢?
想要保證緩存與數(shù)據(jù)庫的雙寫一致,一共有4種方式,即4種同步策略:
那么我們需要做的就是根據(jù)不同的場景來使用合理的方式來解決數(shù)據(jù)問題。
第一種:先刪除緩存,再更新數(shù)據(jù)庫
在出現(xiàn)失敗時可能出現(xiàn)的問題:
1:線程A刪除緩存成功,線程A更新數(shù)據(jù)庫失敗;
2 :線程B從緩存中讀取數(shù)據(jù);由于緩存被刪,進(jìn)程B無法從緩存中得到數(shù)據(jù),進(jìn)而從數(shù)據(jù)庫讀取數(shù)據(jù);此時數(shù)據(jù)庫中的數(shù)據(jù)更新失敗,線程B從數(shù)據(jù)庫成功獲取舊的數(shù)據(jù),然后將數(shù)據(jù)更新到了緩存。
最終,緩存和數(shù)據(jù)庫的數(shù)據(jù)是一致的,但仍然是舊的數(shù)據(jù)。
第二種:先更新數(shù)據(jù)庫,再刪除緩存
假設(shè)這會有兩個請求,一個請求A做查詢操作,一個請求B做更新操作,那么會有如下情形產(chǎn)生
(1)緩存剛好失效
(2)請求A查詢數(shù)據(jù)庫,得一個舊值
(3)請求B將新值寫入數(shù)據(jù)庫
(4)請求B刪除緩存
(5)請求A將查到的舊值寫入緩存
如果發(fā)生上述情況,確實是會發(fā)生臟數(shù)據(jù)。
然而,發(fā)生這種情況的概率又有多少呢?
發(fā)生上述情況有一個先天性條件,就是步驟(3)的寫數(shù)據(jù)庫操作比步驟(2)的讀數(shù)據(jù)庫操作耗時更短,才有可能使得步驟(4)先于步驟(5)。
數(shù)據(jù)庫的讀操作的速度遠(yuǎn)快于寫操作的(不然做讀寫分離干嘛,做讀寫分離的意義就是因為讀操作比較快,耗資源少),因此步驟(3)耗時比步驟(2)更短,這一情形很難出現(xiàn)。
先更新數(shù)據(jù)庫,再刪緩存依然會有問題,不過,問題出現(xiàn)的可能性會因為上面說的原因,變得比較低。
第三種:給所有的緩存一個失效期
第三種方案可以說是一個大殺器,任何不一致,都可以靠失效期解決,失效期越短,數(shù)據(jù)一致性越高。但是失效期越短,查數(shù)據(jù)庫就會越頻繁。因此失效期應(yīng)該根據(jù)業(yè)務(wù)來定。
1.并發(fā)不高的情況:
讀: 讀redis->沒有,讀mysql->把mysql數(shù)據(jù)寫回redis,有的話直接從redis中取;
寫: 寫mysql->成功,再寫redis;
2.并發(fā)高的情況:
讀: 讀redis->沒有,讀mysql->把mysql數(shù)據(jù)寫回redis,有的話直接從redis中取;
寫:異步話,先寫入redis的緩存,就直接返回;定期或特定動作將數(shù)據(jù)保存到mysql,可以做到多次更新,一次保存;
第四種:加鎖,使線程順序執(zhí)行
如果一個服務(wù)部署到了多個機器,就變成了分布式鎖,或者是分布式隊列按順序去操作數(shù)據(jù)庫或者 Redis,帶來的副作用就是:數(shù)據(jù)庫本來是并發(fā)的,現(xiàn)在變成串行的了,加鎖或者排隊執(zhí)行的方案降低了系統(tǒng)性能,所以這個方案看起來不太可行。
第五種:采用雙刪
先刪除緩存,再更新數(shù)據(jù)庫,當(dāng)更新數(shù)據(jù)后休眠一段時間再刪除一次緩存。
方案推薦兩種:
1:項目整合quartz等定時任務(wù)框架,去實現(xiàn)延時3--5s再去執(zhí)行最后一步任務(wù) 。(推薦使用)
2:創(chuàng)建線程池,線程池中拿一個線程,線程體中延時3-5s再去執(zhí)行最后一步任務(wù)(不能忘了啟動線程)
第六種:異步更新緩存(基于訂閱binlog的同步機制)
MySQL binlog增量訂閱消費+消息隊列+增量數(shù)據(jù)更新到redis讀Redis
熱數(shù)據(jù)基本都在Redis寫MySQL:增刪改都是操作MySQL更新Redis數(shù)據(jù):MySQ的數(shù)據(jù)操作binlog,來更新到Redis:
1)數(shù)據(jù)操作主要分為兩大塊:一個是全量(將全部數(shù)據(jù)一次寫入到redis)一個是增量(實時更新)。
這里說的是增量,指的是mysql的update、insert、delate變更數(shù)據(jù)。
2)讀取binlog后分析 ,利用消息隊列,推送更新各臺的redis緩存數(shù)據(jù)。
這樣一旦MySQL中產(chǎn)生了新的寫入、更新、刪除等操作,就可以把binlog相關(guān)的消息推送至Redis,Redis再根據(jù)binlog中的記錄,對Redis進(jìn)行更新。
其實這種機制,很類似MySQL的主從備份機制,因為MySQL的主備也是通過binlog來實現(xiàn)的數(shù)據(jù)一致性。
這里可以結(jié)合使用canal(阿里的一款開源框架),通過該框架可以對MySQL的binlog進(jìn)行訂閱,而canal正是模仿了mysql的slave數(shù)據(jù)庫的備份請求,使得Redis的數(shù)據(jù)更新達(dá)到了相同的效果。
當(dāng)然,這里的消息推送工具你也可以采用別的第三方:kafka、rabbitMQ等來實現(xiàn)推送更新Redis。
以上就是動力節(jié)點小編介紹的"redis緩存怎么和數(shù)據(jù)庫同步到一致性呢",希望對大家有幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為您務(wù)。
初級 202925
初級 203221
初級 202629
初級 203743