Redis 緩存的常用設計模式

Redis 緩存的常用設計模式:

一. 寫操作:

  • 以 Redis 統一視圖爲準:先更新緩存,後更新數據庫。
  1. Write Through Pattern 直寫模式:

    首先將數據寫入緩存,再將數據立即同步到數據庫。

  1. Write Behind Pattern 寫後模式:

    首先將數據寫入緩存,再將數據異步的批量同步到數據庫。

  • 寫操作不經過緩存。
  1. Write Around Pattern 繞寫模式:

    數據直接寫入數據庫,不經過緩存。

二. 讀操作:

4)Read Through Pattern 讀穿透:

    如果緩存未命中,緩存層自動從數據庫中獲取數據,然後將數據寫入緩存中,最終由緩存返回數據給應用程序。

緩存系統自動處理數據加載,使得數據的讀寫操作對應用更加透明,通常與 write Through 結合使用,這意味這所有的操作都會通過緩存層。

三. 讀寫操作:

5)Cache Aside Pattern 旁路模式:

    緩存操作是由應用程序顯式控制的,開發者可以根據特定業務需求來自定義管理緩存數據,更加靈活可控。

 一.  Write Through Pattern


寫穿透模式 (直寫模式):在這種模式下,應用程序在寫數據時,首先將數據寫入緩存,然後再將數據立即寫入到數據庫,確保數據庫和緩存中的數據保持一致。

步驟

  1. 應用程序發起寫操作。

2. 首先將數據寫入緩存。

3. 再將數據立即寫入到數據庫。

先更新緩存再立即更新數據庫

優點

數據一致性:每次寫操作都要同時更新緩存和數據庫,保證了緩存和數據庫之間的數據一致性。

即時的數據訪問:由於緩存始終保持最新狀態,讀取操作可以立即從緩存中獲取最新的數據,提高了數據訪問的速度。

缺點

寫操作延遲:對於寫操作頻繁的場景,每次寫操作都要同時更新緩存和數據庫,導致寫操作延遲。

資源消耗:緩存和數據庫的同步更新會消耗更多的計算和內存資源。

適用場景

適用於對數據一致性要求較高,寫操作不頻繁的場景。

例如:電商平臺的訂單處理,當用戶下單時,訂單信息既寫入緩存,也同步寫入數據庫,保證了數據的實時性和一致性。

 二.  Write Behind  Pattern


寫後模式:在這種模式下,應用程序在寫數據時,首先將數據寫入緩存,然後再將數據異步的批量寫入到數據庫。

步驟

  1. 應用程序發起寫操作。

2. 首先將數據寫入緩存。

3. 再將數據異步的批量寫入到數據庫。

先更新緩存再異步更新數據庫

優點

提高寫操作性能:寫操作首先發生在緩存中,通常比寫入數據庫快得多。

減輕數據庫負載:異步批量寫入數據庫,減少對數據源的即時寫操作。

提高響應時間:寫操作首先發生在緩存中,可以更快的響應寫請求。

缺點

數據一致性問題:由於數據是異步寫入數據庫的,導致緩存和數據庫之間在一定時間內的數據不一致。

適用場景

適用於寫操作遠多於讀操作,且對數據一致性****要求不高的場景。

例如:用戶行爲日誌收集,用戶在網站上的點擊行爲被記錄在緩存中,然後異步批量寫入到日誌數據庫。

 三.  Write  Around Pattern


繞寫模式:在這種模式下,應用程序在寫數據時,直接將數據寫入數據庫,寫操作不經過緩存(寫數據繞過緩存),緩存僅用於讀取操作。

優點

提高緩存效率:寫操作不需要同步到緩存,緩存不會應爲寫操作而頻繁的失效或更新。

提高內存利用率:防止那些不會再次被讀取到的數據佔用緩存空間,提高資源利用率。

缺點

無法保障數據一致性:如果更新的數據同時存在於緩存和數據庫中,則會造成緩存和數據庫中的數據不一致。由於緩存數據沒有被及時更新,導致從緩存中獲取到髒數據。

適用場景

適用於數據寫入****後很少被讀取的場景。

例如:對於數據備份操作直接寫入到備份存儲中,不經過緩存;或者是針對報告、歸檔信息的操作。

 四.  Read Through Pattern


讀穿透模式:在這種模式下,應用程序在讀數據時,首先直接對緩存發起請求 (先查緩存),如果緩存未命中 (緩存中不存在該數據),緩存中間件會自動觸發一個回源操作,從數據庫或其它數據源中獲取數據,然後將數據寫入緩存中,最終由緩存返回數據給應用程序。

步驟

  1. 應用程序請求讀數據。

  2. 首先查詢緩存中是否有數據的鍵存在。

  3. 如果緩存命中 (緩存中存在該數據),則直接從緩存中獲取數據,返回給應用程序。

  4. 如果緩存未命中,緩存層會從數據庫中獲取數據。

  5. 將數據寫入緩存。

  6. 緩存返回新加載的數據給應用程序。

優點

降低數據庫的負載:一旦數據被加載到緩存中,後續的讀取請求將直接從緩存中獲取數據,減少了對數據庫的直接訪問。

提高系統的性能和併發讀取能力:讀操作從緩存中進行,緩存的讀取速度快,從而提高了系統的性能。

缺點

高併發請求下的數據不一致:連續兩次寫入請求,由於寫入操作存在先後順序問題,當數據被更新時,其它併發請求可能還在讀取緩存中的舊數據,導致數據不一致。

回源延遲:如果緩存未命中,回源操作會導致數據的獲取有一定的延遲,特別是當數據量較大時,延遲會更加明顯。

解決方案

設置合適的緩存數據過期時間,採用適當的緩存數據過期策略和緩存淘汰策略確保緩存的有效性。

“定期刪除 + 惰性刪除” 策略:用於刪除過期的緩存數據。 

內存淘汰策略:用於在內存不足時,選擇要淘汰的緩存數據。

適用場景

適用於讀取頻繁寫入較少,對數據一致性要求不高,對速度和性能要求較高的場景。

緩存中放的是當前在線用戶的活躍數據,例如遊戲中的換皮膚、換裝備,用戶登錄系統後,用戶的所有行爲在緩存中生成副本(統一視圖)。

 五.  Cache Aside Pattern


旁路緩存模式:在這種模式下,讀數據時先查詢緩存,緩存命中則直接返回數據;緩存未命中,則查詢數據庫,查詢成功後,更新緩存中的數據。

寫數據時先更新數據庫,更新成功後刪除緩存。

讀數據

  1. 首先查詢緩存中是否有數據的鍵存在。

  2. 如果緩存命中,則直接從緩存中獲取數據,返回給應用程序。

  3. 如果緩存未命中,則從數據庫中查詢數據。

  4. 查詢成功後,將數據寫入緩存。

  5. 最後,將數據返回給應用程序。

寫****數據

  1. 直接將數據寫入數據庫。

  2. 寫數據庫成功後,刪除緩存。

優點

確保緩存中存放的是真熱點數據:只有在實際需要時,才加載數據到緩存,避免緩存中填充未使用或很少使用的數據,保證緩存中存放的是當前窗口的活躍數據。

內存佔用小:只緩存真正的熱點數據,減少緩存空間的浪費,更有效的利用緩存空間。

提高靈活性:緩存操作是由應用程序顯式控制的,開發者可以根據特定業務需求來管理緩存數據。

缺點

代碼複雜性:需要額外的代碼邏輯去處理緩存的加載和失效。

數據一致性問題:由於緩存更新依賴於應用程序邏輯,如果處理不當,可能會導致緩存和數據庫之間的數據不一致。

適用場景

適用於讀多****寫少,對數據實時性要求不高的場景。

例如:新聞內容展示、博客文章的閱讀。

如果緩存刪除失敗設置****緩存過期時間兜底。---- 保證****最終一致性

一. 緩存數據的類型

1) 靜態緩存數據

例如:字典表,靜態緩存數據沒有時間窗口,即沒有設置過期時間。

  1. 動態的緩存

當前窗口的活躍數據,需要設置合適的緩存過期時間。

2. 過期時間的設置

建議:過期時間 <= 業務時間 — 續期

總結:

即使緩存刪除失敗了,這個緩存數據也是帶有過期時間的,採用 “定期刪除 + 惰性刪除” 的策略。

定期刪除:Redis 默認每隔 100ms 就隨機抽取一些設置了過期時間的 key,檢查其是否過期,如果有過期就刪除。 定期刪除可能會導致很多過期的 key 到了時間並沒有被刪除掉,此時就要用到惰性刪除。

惰性刪除:在你請求某個 key 的時候,redis 會檢查這個 key 是否設置了過期時間,並判斷是否過期了,如果過期就刪除。

所謂延時雙刪:

A 讀數據 --> 發現緩存失效了 --> A 讀數據庫 (假設讀到 5) --> 更新緩存(緩存中數據爲 5)

在 A 讀數據後到更新緩存的過程中,發生了:

B 寫數據 ----> 寫入數據庫 (數據庫中值被更新爲 6) ---> 刪除緩存

這個寫操作正好卡在 A 讀後到更新的過程中。

於是有人提出了延時雙刪:

先更新數據庫 --> 更新成功後,立刻刪除緩存 --> 延時後再刪除緩存

延時雙刪並沒有徹底解決問題,也帶來了數據延時一致性的窗口期。

所以增加延時雙刪反而使得問題更復雜了,還不如直接給緩存中的數據設置合適的過期時間,採用緩存淘汰策略兜底。

即使有第三方直接更新了數據庫,而不是通過請求進來更新的,用設置緩存數據過期時間兜底的方案仍然可以解決問題。

​​

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/apwlJ9ui-yLob0qgT7R2uA