Redis 缓存实战——缓存、数据库一致性问题分析与解决方案
引言
緩存與數據庫一致性的問題自從出現了緩存概念后就一直被提及,它是一個緩存方案的先天缺陷,只要存在緩存,就勢必會討論緩存與數據庫一致性的問題。
一致性問題還廣泛存在于各種分布式存儲場景中,如主從一致性等等。
本篇博客討論和整理了緩存、數據庫一致性問題的一些思路,在實際的緩存業務場景中,可以對技術實現的起到一定指導作用。
一、為什么會出現一致性問題
緩存作為應用程序與數據庫之間的數據存儲池,主要作用就是熱數據備份的作用,它的主要目的就是提高熱數據的查詢效率。因此,在讀取緩存方面,普遍的做法是沒有疑問的,基本都是按照如下流程執行:
在寫數據方面,卻存在很多問題,其中一點就是——如何保證數據庫的數據與緩存的數據保持一致。
二、強一致性、弱一致性、最終一致性
在一致性問題上,分為事務一致性和數據一致性,而緩存、數據庫一致性很明顯就是數據一致性。
其實只有兩類數據一致性,強一致性和弱一致性。除此之外,所有其他的一致性都是弱一致性的特殊情況。
2.1 強一致性與弱一致性
強一致性又叫線性一致性,顧名思義,就是在多個數據源之間以同步的方式復制數據。
弱一致性,即復制是異步的。在時間中,我們通常使一個從庫是同步的,而其他的則是異步的。如果這個的從庫出現問題,則使另一個異步從庫同步。
這樣可以確保永遠有兩個節點擁有完整數據。主庫和同步從庫,這種配置成為半同步。
2.2 最終一致性
最終一致性表示不一致的狀態可能會出現,但這也只是暫時的,不同的數據源會在未來某個時點保持同步。
而為緩存設置過期時間可以有效的保證最終一致性。
三、緩存更新策略
解決緩存、數據庫一致性問題的方法,無非就是在更新數據庫時盡可能的減少不一致的情況出現。
但只要存在緩存,就無法保證數據的強一致性,選擇不同的緩存更新策略,也只是在弱一致性的前提下,盡可能保證數據的同步,或達到最終一致性。
從理論上來講,共有四種更新策略:
一般情況下,為了保證數據的安全,都會第一時間將數據更新到數據庫中,所以先操作緩存的方式往往不被采納。
對于先更新數據庫的情況,到底是選擇更新緩存還是刪除緩存呢?
3.1 先更庫,更緩存
結論是,這種方案普遍不被采納。
第一點原因,線程安全性,如果同時有請求A 和 請求 B 都要更新數據,那么會出現如下情況:
本來按照先后順序,A的更新操作在 B 之前,最終也應該是緩存中存放 B 更新的數據,但是由于一些特殊原因,導致后更新數據的 B 先于 A 更新了緩存,就導致了臟數據。
第二點原因,如果是一個寫多讀少的場景,采用這種方案由于每次更新數據都要去更新緩存,但從緩存中查詢的次數卻寥寥無幾,不僅沒有起到提高查詢性能的目的,反而還極大的浪費性能。
3.2 先更庫,刪緩存
該方案同樣會導致數據不一致。例如,同時有一個請求 A 查詢數據,另一個請求 B 更新數據,會產生如下情形:
上面的情況是有可能發生的,它產生的原因是由于 A 將取得的舊數據(在 B 更新完數據并執行了刪除緩存操作之后)又放入到了緩存,即緩存中的數據是 A 之前取得的舊數據。
但是這種情況發生的概率很低,這是因為寫庫操作的速度要遠低于讀庫的速度。正因為如此,請求 B 在將新數據寫入到數據庫后才會大概率在請求 A 將舊數據寫入緩存之后執行刪除緩存操作。
即大概率發生的情形應該是:
由于寫庫操作要更加緩慢,因此,大概率會在最后,在其他讀操作的寫入緩存執行后再將緩存刪除,從而保證數據的一致性。
另外,更新緩存實際上可以看做是先刪除再添加的兩步操作,那么對于刪緩存的操作,無非就是將添加緩存安排到了下次查詢的時候,這也在查詢情況較少的時候避免了頻繁更新緩存的尷尬。
因此,先更庫,再刪除緩存是一種較為可行的解決一致性問題的方案。
四、先更庫再刪緩存的其他問題
如果緩存刪除失敗了怎么辦?
的確,如果更新了數據庫之后,由于特殊原因,導致緩存刪除失敗,緩存中依然保留了舊數據,那么同樣存在不一致的問題。
這個時候,我們需要為業務系統增加全局的緩存失效時間,這樣可以保證不一致也只是暫時的,即達到最終一致性的效果。
或者使用下面的解決方案,使用消息隊列保存數據庫更新后失敗的緩存刪除操作,再某一時點進行重試,其中 binlog 訂閱程序可以選擇現成的MySQL binlog訂閱中間件 “canal”。
鳴謝:
《緩存與數據庫的一致性問題解析》
總結
以上是生活随笔為你收集整理的Redis 缓存实战——缓存、数据库一致性问题分析与解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: fft之后求模值和相位_如何利用相位噪声
- 下一篇: 方正高影仪安装方法_铝合金门窗是怎么安装