如何保證Redis快取和資料庫的雙寫一致性?

2021-10-03 02:59:37 字數 2564 閱讀 7216

在資料庫+快取模式下,當資料庫中的資料需要更新時,快取裡的資料怎麼處理?如何保證快取和資料庫中資料的一致性?常用的解決方案有兩種(其他渣渣的方案這裡不討論):

1、先刪除快取,再更新資料庫;

2、先更新資料庫,再刪除快取;

下面我們就來看一下這兩種方案,看看它們是怎麼保證資料一致性的?

理想的流程是這樣的:先刪除快取,再更新資料庫,更新完資料庫後,當有請求進來的時候發現快取中沒有資料,於是去查資料庫,讀取到更新後的新資料放回快取再返回。這只是理想化的流程,如果只是簡單的這樣做,我們看看會存在什麼問題呢?

這個問題可以用"延時雙刪策略"來解決,a執行緒先刪除快取,再更新資料庫,資料庫更新完成後休眠200ms,再次刪除快取,這樣做的目的就是保證中間產生的髒資料最後被再次刪除。但這個200ms要根據自己的業務情況來確定。

還有乙個問題,在延時雙刪策略第二次刪除快取的時候刪除失敗怎麼辦?這種情況可以提供乙個"重試保障機制",如果刪除失敗,可以將刪除失敗的key傳送到訊息佇列,再次重試操作。

理想的流程是這樣的:先更新資料庫,再刪除快取,當再有請求進來的時候發現快取中沒有資料,於是去查資料庫,再將更新後的新資料放到快取返回。

這種策略就是典型的「cache aside 模式」,更新快取的設計模式有四種:cache aside, read through, write through和write behind caching。這四種模式並不僅僅適用於資料庫和快取之間的更新,它們設計的初衷是基於計算機體系結構的,比如cpu的快取,硬碟檔案系統中的快取,硬碟上的快取,資料庫中的快取等。所以,它們都是非常權威的,而且歷經了長時間考驗的最佳實踐,我們直接遵從就可以了,沒必要重複造輪子。

推薦閱讀:《快取更新的套路-

facebook在**《scaling memcache at facebook》中說過,他們採用的就是cache aside 策略。

※ 先更新資料庫,再刪除快取有什麼問題?

1、併發問題

從理論上來講,cache aside也有可能發生併發問題,假設有兩個執行緒,a執行緒讀取資料,沒有命中快取,然後就去查資料庫,在a查詢資料庫還沒有返回結果的時候,另乙個執行緒b執行乙個寫操作,更新完資料庫後,讓快取失效(實際上這時候快取已經是失效的,因為a在讀的時候就沒有命中快取),然後,之前的執行緒a讀取資料庫返回了結果,再把老的資料放進快取,這時候快取中放得是a讀出來的老資料,而資料庫中存的是b更新後的新資料,資料庫和快取資料不一致。

這種情況理論上會出現,不過,實際上出現的概率可能非常非常低。因為上述併發場景的出現,需要同時具備條件:1、某執行緒在讀快取時快取失效了,而且剛好併發著有乙個寫操作;2、讀操作在寫操作之前開始,在寫操作之後結束,也就是說讀操作的耗時大於寫操作;出現這種場景的概率還是很低的。

如果要解決cache aside的併發問題,可以通過2pc或是paxos協議保證一致性,或者盡力的降低併發時髒資料的概率,而facebook使用的就是降低概率的玩法,因為2pc太慢,而paxos太複雜。

2、資料庫更新成功,刪除快取失敗怎麼辦?

如果發生這種情況,資料庫中存放的是更新後的資料,快取因為沒有刪除成功存放的還是老資料,這個問題怎麼解決呢,我們可以提供一種保障性的"重試機制"。

方案

一、基於mo實現

(1).更新資料庫資料;

(2).刪除快取失敗;

(3).當刪除快取資料失敗時,應用程式傳送訊息,將需要刪除的 key 傳送到mq中;

(4).應用程式自己消費訊息;

(5).應用接收到訊息後,再次嘗試刪除快取,如果再次刪除失敗,可重發訊息多次嘗試;

方案二,基於 阿里canal 實現

canal是阿里開發的基於資料庫增量日誌解析,提供增量資料的訂閱&消費的中介軟體,目前主要支援mysql的binlog解析。從下圖可以看出,基於canal的實現方案完全避免了對業務**的侵入,核心業務**只管更新資料庫,其他的不用care。

(1).更新資料庫資料;

(2).mysql 將資料更新日誌寫入 binlog 中;

(3).canal 訂閱 & 消費 mysql binlog;

(4).canal 解析binlog,提取出​更新資料的key傳送給另一段非業務**;

(5).非業務**嘗試刪除快取操作,發現刪除失敗;

(6).將需要刪除快取的 key 傳送到訊息佇列 (mq) 中;

(7).消費訊息,從佇列中拿到要刪除的快取key;

(8).拿到要刪除的key後,再次嘗試刪除快取,如果再次刪除失敗,可重發訊息多次嘗試;

總的來說就是先更新資料庫,再刪除快取,提供乙個"重試保障機制",如果刪除快取失敗時,可以將刪除失敗的key傳送到訊息佇列,再進行重試刪除操作。 

redis快取如何同步資料庫

redis快取如何同步資料庫 redis mysql模式 讀 服務程式先從快取中讀取資料,如果命中,則將資料讀出。如果未命中,則在資料庫中讀取資料,然後將資料寫入到快取中去。更新資料 常見的模式是先到資料庫中寫入,然後刪除快取中的資料。產生的不一致 讀 只是讀資料一般不會有不一致出現。更新 1 資料...

Redis 如何保證快取和資料一致性

不一致問題 缺點 如果在修改資料庫之後更新快取之前出現問題,出現資料不一致 解決方案 先刪除快取,再修改資料庫 缺點 如果在刪除快取之後修改資料庫之前,出現另乙個執行緒去讀快取發現快取為空,又從資料庫拉取還沒被修改的舊資料到快取,導致資料不一致 注 只有在對乙個資料在併發的進行讀寫的時候,才可能會出...

如何更新快取保證快取和資料庫雙寫一致性?

在專案中快取是經常用到的,為了減少和資料庫的互動,小夥伴們利用快取的思路如下 我們小夥伴們有沒有考慮到快取更新的問題,小夥伴們肯定會說肯定用過啊,有資料更新時,把快取清空掉就行了啊,下一次訪問的時候服務就會把新值設定到快取中了。這樣不就行了嗎?對的,在一般專案中,這樣的使用就夠了。那麼大家看看在高併...