詳談redis跟數(shù)據(jù)庫(kù)的數(shù)據(jù)同步問(wèn)題
一、Redis 數(shù)據(jù)庫(kù)數(shù)據(jù)一致性的解決方案
在修改數(shù)據(jù)的時(shí)候,通常面臨著雙寫(xiě)的問(wèn)題,也就是redis中要更新數(shù)據(jù),數(shù)據(jù)庫(kù)中也要更新數(shù)據(jù),對(duì)于這個(gè)問(wèn)題redis、數(shù)據(jù)庫(kù)的數(shù)據(jù)同步方案有四種:
- 先更新Redis緩存,再更新數(shù)據(jù)庫(kù)
- 先更新數(shù)據(jù)庫(kù),再更新Redis緩存
- 先刪除Redis中的緩存,再更新數(shù)據(jù)庫(kù)
- 先更新數(shù)據(jù)庫(kù),在刪除Redis緩存
從上面的解決方案來(lái)看,先不說(shuō)Redis、數(shù)據(jù)庫(kù)的操作先后,數(shù)據(jù)庫(kù)的操作始終都是更新,但是Redis不一樣,Redis有兩種方案,一是更新(也就是直接在Redis中寫(xiě)入更新的數(shù)據(jù)),二是刪除Redis中的緩存,那么接下來(lái)我們就看看這兩者有什么區(qū)別
1.1、更新Redis緩存、刪除Redis緩存的區(qū)別
更新Redis緩存
- 優(yōu)點(diǎn):每次數(shù)據(jù)變化都及時(shí)更新緩存,所以查詢時(shí)不容易出現(xiàn)未命中的情況
- 缺點(diǎn):更新緩存的消耗比較大。如果數(shù)據(jù)要經(jīng)過(guò)復(fù)雜的計(jì)算再寫(xiě)入緩存,那么頻繁的更新緩存,就會(huì)影響服務(wù)器的性能。又因?yàn)镽edis是單線程的,所以如果是寫(xiě)入數(shù)據(jù)頻繁的業(yè)務(wù)場(chǎng)景,那么可能頻繁的更新緩存時(shí),卻沒(méi)有多余的線程讀取該數(shù)據(jù)。
刪除Redis緩存
- 優(yōu)點(diǎn):操作簡(jiǎn)單,無(wú)論更新操作是否復(fù)雜,都是將緩存中的數(shù)據(jù)直接刪除
- 缺點(diǎn):刪除緩存后,下一次查詢緩存會(huì)出現(xiàn)未命中,這時(shí)需要重新讀取一次數(shù)據(jù)庫(kù)。從上面的比較來(lái)看,一般情況下,刪除緩存是更有的方案
所以經(jīng)過(guò)這兩個(gè)區(qū)別的比較,我們只會(huì)采取刪除Redis緩存的兩個(gè)方案,接下來(lái)就是比較這兩個(gè)方案會(huì)產(chǎn)生什么樣的問(wèn)題,哪一個(gè)方案產(chǎn)生的問(wèn)題比較容易解決
二、先刪Redis緩存、后刪Redis緩存會(huì)產(chǎn)生什么問(wèn)題?解決方案?
2.1、刪除Redis緩存,再更新數(shù)據(jù)庫(kù)

從上面的圖可以知道,如果更新數(shù)據(jù)庫(kù)失敗的話,那么即使刪除Redis緩存成功了,在重試期間,下一次讀取出來(lái)的數(shù)據(jù)還是之前的舊數(shù)據(jù),即使重試成功了,數(shù)據(jù)庫(kù)的數(shù)據(jù)更新了,但是Redis中已經(jīng)被重新緩存了舊數(shù)據(jù),這樣兩邊的數(shù)據(jù)就不會(huì)一致
2.2、解決方案
從上面的問(wèn)題可以知道,問(wèn)題就出現(xiàn)在進(jìn)行修改數(shù)據(jù)庫(kù)重試期間,有線程訪問(wèn)Redis,而此時(shí)Redis中沒(méi)有數(shù)據(jù),就會(huì)從數(shù)據(jù)庫(kù)中拿數(shù)據(jù),而此時(shí)的數(shù)據(jù)還是舊數(shù)據(jù),就導(dǎo)致Redis重新緩存了舊數(shù)據(jù),等重試成功之后導(dǎo)致數(shù)據(jù)庫(kù)跟Redis緩存數(shù)據(jù)不一致
這個(gè)問(wèn)題的解決方案就是采用延遲雙刪的方案來(lái)解決
延遲雙刪的主要思想就是,在數(shù)據(jù)庫(kù)中的數(shù)據(jù)更新成功之后,再啟動(dòng)一個(gè)延時(shí)線程來(lái)刪除Redis中的緩存,那么之后讀取的數(shù)據(jù)就是更新后的數(shù)據(jù)了,完整的流程應(yīng)該是:
- 先刪一次Redis的緩存
- 更新數(shù)據(jù)庫(kù)中的數(shù)據(jù)
- 可以使用sleep方法讓線程睡一會(huì)
- 然后再刪除一個(gè)Redis的緩存
2.3、先更新數(shù)據(jù)庫(kù),再刪除Redis緩存

如上圖,是先更新數(shù)據(jù)庫(kù)再刪除緩存,在出現(xiàn)失敗時(shí)可能出現(xiàn)的問(wèn)題:
- 線程A更新數(shù)據(jù)庫(kù)成功,線程A刪除緩存失??;
- 線程B讀取緩存成功,由于緩存刪除失敗,所以線程B讀取到的是緩存中舊的數(shù)據(jù)。
- 最后線程A刪除緩存成功,有別的線程訪問(wèn)緩存同樣的數(shù)據(jù),與數(shù)據(jù)庫(kù)中的數(shù)據(jù)是一樣。
- 最終,緩存和數(shù)據(jù)庫(kù)的數(shù)據(jù)是一致的,但是會(huì)有一些線程讀到舊的數(shù)據(jù)。
這個(gè)方案影響就會(huì)比較小一點(diǎn),可以只采取重試機(jī)制就可以解決上面的問(wèn)題,但是先刪除Redis緩存的那個(gè)方案不同,即使采取了重試機(jī)制過(guò)后,很有可能還是會(huì)產(chǎn)生數(shù)據(jù)不一致的情況,所以加了一個(gè)延遲雙刪的方案
比較兩個(gè)方案的誰(shuí)更好
先刪除Redis的那個(gè)方案即使所有的操作都是成功的,但是在分布式場(chǎng)景下,有可能會(huì)導(dǎo)致高并發(fā)問(wèn)題的產(chǎn)生,也就是說(shuō)可能會(huì)在更新數(shù)據(jù)庫(kù)數(shù)據(jù)的同時(shí)有線程會(huì)訪問(wèn)數(shù)據(jù),這也就會(huì)導(dǎo)致數(shù)據(jù)不一致的問(wèn)題
而先刪除數(shù)據(jù)庫(kù)則不一樣,即使在更新數(shù)據(jù)庫(kù)的時(shí)候發(fā)生了高并發(fā)問(wèn)題也不影響,因?yàn)榉凑峦陻?shù)據(jù)庫(kù)之后還是會(huì)刪除Redis中的緩存,有影響的也僅僅只是在高并發(fā)產(chǎn)生的那部分線程而已,所以很明顯第二個(gè)方案影響更小
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
無(wú)法啟動(dòng)Redis打開(kāi)redis-server閃退的問(wèn)題解決辦法
正常開(kāi)啟redis服務(wù),首先要啟動(dòng)redis-server.exe,但是閃退,導(dǎo)致無(wú)法開(kāi)啟redis服務(wù),這篇文章主要給大家介紹了關(guān)于無(wú)法啟動(dòng)Redis打開(kāi)redis-server閃退問(wèn)題的解決辦法,需要的朋友可以參考下2024-07-07
設(shè)置Redis最大占用內(nèi)存的實(shí)現(xiàn)
本文主要介紹了設(shè)置Redis最大占用內(nèi)存的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
Redis緩存lettuce更換為Jedis的實(shí)現(xiàn)步驟
使用寶塔在服務(wù)器上配置Redis的詳細(xì)圖文教程
淺談Redis中的內(nèi)存淘汰策略和過(guò)期鍵刪除策略
詳解redis desktop manager安裝及連接方式
SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象的操作方法

