緩存和數據庫一致性分析之三種緩存策略


一、背景介紹

  公司最近需要對DB使用進行優化,對於訪問頻繁的接口需要加上緩存。那么這自然會涉及到一個問題:緩存和數據庫一致性問題。本文針對這個問題進行討論,並介紹3種常用的緩存模式。

  緩存由於其高並發和高性能的特性,已經在項目中被廣泛使用,在緩存的使用中,通常會面臨一個更新的問題,當數據源產生變化,如何去更新到數據庫與緩存之中,並且盡量保證安全與性能。

二、Cache Aside模式

  Cache-Aside可能是項目中最常見的一種模式,它是一種控制邏輯實現在應用程序中的模式。緩存不和數據庫直接進行交互,而是由應用程序來同時和緩存以及數據庫打交道。Cache-Aside的名字正體現了這個模式,Cache在應用的一旁(aside)。  

讀數據時:

  1. 程序需要判斷緩存中是否已經存在數據。
  2. 當緩存中已經存在數據(也就是緩存命中,cache hit),則直接從緩存中返回數據
  3. 當緩存中不存在數據(也就是緩存未命中,cache miss),則先從數據庫里讀取數據,並且存入緩存,然后返回數據

寫數據時,有兩種可選的方案,但推薦第二種方案:

第一種寫數據方案:

  1. 先更新數據庫/緩存
  2. 再更新緩存/數據庫

但這種方案有線程安全的問題,可能出現緩存和數據庫不一致。試想有兩個寫的線程,線程A和線程B

  1. A寫數據庫
  2. B后於A寫數據庫
  3. B寫緩存
  4. A寫緩存
  5. 緩存和數據庫中的數據不一致,緩存中的是臟數據

要解決線程安全的問題,我們可以加鎖,不過實現起來比較麻煩,因此我們不考慮這種寫數據方案。

第二種寫數據方案(推薦):

  1. 先更新數據庫
  2. 再刪除緩存中對應的數據

 

那么這種寫方案會有線程安全的問題嗎?有,試想一下有兩個線程,線程A讀,線程B寫

  1. A讀數據,由於未命中那么從數據庫中取數據
  2. B寫數據庫
  3. B刪除緩存
  4. A由於網絡延遲比較慢,將臟數據寫入緩存

但是這種情況可能性非常的小,需要同時滿足很多條件,幾乎不太可能發生,所以我們一般都采用這種寫方案。另外可以對緩存中的數據設置合適的過期時間,即使發生的臟數據的情況,也不會發生很長時間。

緩存刪除失敗的解決方案:

  如果更新完數據庫之后,刪緩存失敗,那么就會導致讀取的數據仍然是舊數據。此時解決方案就是利用消息隊列進行刪除的補償,如圖所示。具體的業務邏輯用語言描述如下:

  • 請求 A 先對數據庫進行更新操作
  • 在對 Redis 進行刪除操作的時候發現報錯,刪除失敗
  • 此時將Redis 的 key 作為消息體發送到消息隊列中
  • 系統接收到消息隊列發送的消息后再次對 Redis 進行刪除操作

2.1、應用場景

  適用於讀多寫少的場景。如果寫操作較多,則會導致緩存中的數據頻繁失效,降低緩存的作用。

2.2、優點

  1. 緩存僅僅保存被請求的數據,屬於懶加載模式(Lazy Loading),和下文的Write-Through模式相比,避免了任何數據都被寫入緩存造成緩存頻繁的更新。

2.3、缺點

  1. 當發生緩存未命中的情況時,則會比較慢,因為要經過三個步驟:查詢緩存,從數據庫讀取,寫入緩存

  2. 如果寫操作較多,則會導致緩存中的數據頻繁失效,降低緩存的作用。

三、Read-Through/Write-Through 模式

  這種模式中,應用程序將緩存作為主要的數據源,而數據庫對於應用程序是透明的,更新數據庫和從數據庫的讀取的任務都交給緩存來代理了,所以對於應用程序來說,簡單很多。

3.1、Read-Through

  由緩存配置一個讀模塊,它知道如何將數據庫中的數據寫入緩存。在數據被請求的時候,如果未命中,則將數據從數據庫載入緩存。

3.2、Write-Through

  緩存配置一個寫模塊,它知道如何將數據寫入數據庫。當應用要寫入數據時,緩存會先存儲數據,並調用寫模塊將數據寫入數據庫。

3.3、應用場景 

   本模式適用於讀多寫少、對數據一致性要求較高的場景。

3.4、優點

  1. 緩存不存在臟數據

  2. 相比較Cache-Aside懶加載模式,讀取速度更高,因為較少因為緩存未命中而從數據庫中查找

  3. 應用程序的邏輯相對簡單

3.5、缺點

  1. 緩存的容量使用較高

  2. 對於總是寫入卻很少被讀取的應用,那么Write-Through會非常浪費性能,因為數據可能更改了很多次,卻沒有被讀取,白白的每次都寫入緩存造成寫入延遲。

四、Write-Back 模式

  本模式又叫做Write-Behind。和Write-Through寫入的時機不同,Write-Back將緩存作為可靠的數據源,每次都只寫入緩存,而寫入數據庫則采用異步的方式,比如當數據要被移除出緩存的時候再存儲到數據庫或者一段時間之后批量更新數據庫。

4.1、應用場景

  讀寫效率都非常好,寫的時候因為異步存儲到數據庫,提升了寫的效率,適用於讀寫密集的應用。

4.2、優點

  1. 寫入和讀取數據都非常的快,因為都是從緩存中直接讀取和寫入。

  2. 對於數據庫不可用的情況有一定的容忍度,即使數據庫暫時不可用,系統也整體可用,當數據庫之后恢復的時候,再將數據寫入數據庫。

  3. 降低了DB的壓力,可以在流量高峰期以緩存為主,等流量過去之后,再慢慢的把數據同步到DB。

4.3、缺點

   1. 有數據丟失的風險,如果緩存掛掉而數據沒有及時寫到數據庫中,那么緩存中的有些數據將永久的丟失了。

五、總結

  分布式系統里要么通過2PC或是Paxos協議保證一致性,要么就是拼命的降低並發時臟數據的概率,緩存系統適用的場景就是非強一致性的場景,所以它屬於CAP中的AP,BASE理論。

  異構數據庫本來就沒辦法強一致,我們只是減少時間窗口,達到最終一致性。每種方案各有利弊,其實每一次的選擇都需要我們對於我們的業務進行評估來選擇,沒有一種技術是對於所有業務都通用的。沒有最好的,只有最適合我們的。


免責聲明!

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



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