背景
在開發過程中,redis緩存技術被大范圍應用。由于現在的系統大多是分布式的,高并發的,redis和傳統的數據庫,存在數據不一致的問題。
解決方案
本文主要探討兩者數據不一致的解決方案:
-
給緩存設置過期時間,保證數據的最終一致性
我們可以對存入緩存的數據設置過期時間,所有的寫操作以數據庫為準,對緩存操作只是盡最大努力。
也就是說如果數據庫寫成功,緩存更新失敗,那么只要到達過期時間,則后面的讀請求自然會從數據庫中讀取新值然后回填緩存。 -
通過合理的更新策略保證數據一致性
- 先更新數據庫,再更新緩存- 先刪除緩存,再更新數據庫- 先刪除緩存,再更新數據庫
方案的可實施性
1.給緩存設置過期時間,保證數據的最終一致性。
這種方案雖然能保證數據的一致性,但是在一定時間范圍內數據存在不一致性
2 更新策略分析
2.1 先更新數據庫,再更新緩存。這種方案看似可行,實際并不可靠。原因如下:
同時有請求A和請求B進行更新操作,那么會出現
1)線程A更新了數據庫
2)線程B更新了數據庫
3)線程B更新了緩存
4)線程A更新了緩存
這就出現請求A更新緩存應該比請求B更新緩存早才對,但是因為網絡,運算等原因,B卻比A更早更新了緩存。這就導致了臟數據,因此不考慮。
2.2 先刪除緩存,再更新數據庫。這種方案也極易導致數據不一致。
如下操作
1)請求A進行寫操作,刪除緩存
2)請求B查詢發現緩存不存在
3)請求B去數據庫查詢得到舊值
4)請求B將舊值寫入緩存
5)請求A將新值寫入數據庫
上述情況就會導致不一致的情形出現。而且,如果不采用給緩存設置過期時間策略,該數據永遠都是臟數據。
如何解決解決這種問題,采用延時雙刪技術。
1)先淘汰緩存
2)再寫數據庫(這兩步和原來一樣)
3)休眠1秒,再次淘汰緩存
有效的將1秒內所造成的緩存臟數據,再次刪除。
2.3 先更新數據庫,再刪除緩存。這種方案是可行性比較高的方案,但也不是絕對的可靠。
兩個線程同時進行寫操作:
1) 線程A更新數據庫
2)線程B更新數據庫
3)線程B刪除緩存
4)線程A刪除緩存
這種情況下不存在問題。但是也存在概率比較低可靠性問題:
1)緩存剛好失效
2)請求A查詢數據庫,得一個舊值
3)請求B將新值寫入數據庫
4)請求B刪除緩存
5)請求A將查到的舊值寫入緩存
這種情況下也會存在臟數據的問題。
為什么這種情況概率比較低?
- 這個條件需要發生在讀緩存時緩存失效,而且并發著有一個寫操作。
- 而實際上數據庫的寫操作會比讀操作慢得多,而且還要鎖表,而讀操作必需在寫操作前進入數據庫操作,而又要晚于寫操作更新緩存,所有的這些條件都具備的概率基本并不大。
那么如何解決?
可以采用延時雙刪除。
1)更新數據庫
2)刪除緩存
3)延時幾秒再次刪除緩存
?