緩存與數據庫的一致性思考


時隔兩年,重新啟動這個博客。熟悉又有點陌生,這兩年我的技術方向有了很大改變,但由於一直在使用為知筆記,因此這些改變沒有提現在本博客上。之所以重啟這個博客,主要是因為博客是一個開放的東西,可以帶來一些交流,而筆記則是個人的東西,缺少思維碰撞。閑話少敘,這就開始。

 

問題:怎么保持緩存與數據庫一致?

 

要解答這個問題,我們首先來看不一致的幾種情況。我將不一致分為三種情況:

1. 數據庫有數據,緩存沒有數據;

2. 數據庫有數據,緩存也有數據,數據不相等;

3. 數據庫沒有數據,緩存有數據。

 

在討論這三種情況之前,先說明一下我使用緩存的策略,也是大多數人使用的策略,叫做 Cache Aside Pattern。酷殼里的 緩存更新的套路 一文,很值得一讀,我的策略也是從他那學來的。

簡而言之,就是

1. 首先嘗試從緩存讀取,讀到數據則直接返回;如果讀不到,就讀數據庫,並將數據會寫到緩存,並返回。

2. 需要更新數據時,先更新數據庫,然后把緩存里對應的數據失效掉(刪掉)。

讀的邏輯大家都很容易理解,談談更新。如果不采取我提到的這種更新方法,你還能想到什么更新方法呢?大概會是:先刪除緩存,然后再更新數據庫。這么做引發的問題是,如果A,B兩個線程同時要更新數據,並且A,B已經都做完了刪除緩存這一步,接下來,A先更新了數據庫,C線程讀取數據,由於緩存沒有,則查數據庫,並把A更新的數據,寫入了緩存,最后B更新數據庫。那么緩存和數據庫的值就不一致了。

另外有人會問,如果采用你提到的方法,為什么最后是把緩存的數據刪掉,而不是把更新的數據寫到緩存里。這么做引發的問題是,如果A,B兩個線程同時做數據更新,A先更新了數據庫,B后更新數據庫,則此時數據庫里存的是B的數據。而更新緩存的時候,是B先更新了緩存,而A后更新了緩存,則緩存里是A的數據。這樣緩存和數據庫的數據也不一致。

按照我提到的這種更新緩存的策略,理論上也是有不一致的風險的,酷殼的文章有提到,只不過概率很小,我們暫時可以不考慮,后面我們有其他手段來補救。

 

討論完使用緩存的策略,我們再來看這三種不一致的情況。

1. 對於第一種,在讀數據的時候,會自動把數據庫的數據寫到緩存,因此不一致自動消除

2. 對於第二種,數據最終變成了不相等,但他們之前在某一個時間點一定是相等的(不管你使用懶加載還是預加載的方式,在緩存加載的那一刻,它一定和數據庫一致)。這種不一致,一定是由於你更新數據所引發的。前面我們講了更新數據的策略,先更新數據庫,然后刪除緩存。因此,不一致的原因,一定是數據庫更新了,但是刪除緩存失敗了。

3. 對於第三種,情況和第二種類似,你把數據庫的數據刪了,但是刪除緩存的時候失敗了。

因此,最終的結論是,需要解決的不一致,產生的原因是更新數據庫成功,但是刪除緩存失敗。

 

我想出的解決方案大概有以下幾種:

1. 對刪除緩存進行重試,數據的一致性要求越高,我越是重試得快。

2. 定期全量更新,簡單地說,就是我定期把緩存全部清掉,然后再全量加載。

3. 給所有的緩存一個失效期。

第三種方案可以說是一個大殺器,任何不一致,都可以靠失效期解決,失效期越短,數據一致性越高。但是失效期越短,查數據庫就會越頻繁。因此失效期應該根據業務來定。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM