高併發場景下,到底先更新緩存仍是先更新數據庫?| 🏆 技術專題第八期徵文

本文 github.com/smileArchit… 已收錄。
JavaMap是Java知識地圖,旨在讓開發者學習不迷路!Java學習請認準JavaMap。git

在大型系統中,爲了減小數據庫壓力一般會引入緩存機制,一旦引入緩存又很容易形成緩存和數據庫數據不一致,致使用戶看到的是舊數據。github

爲了減小數據不一致的狀況,更新緩存和數據庫的機制顯得尤其重要,接下來帶領你們踩踩坑。數據庫

Cache aside

Cache aside也就是旁路緩存,是比較經常使用的緩存策略。緩存

(1)讀請求常見流程微信

Cache aside 讀請求
Cache aside 讀請求

應用首先會判斷緩存是否有該數據,緩存命中直接返回數據,緩存未命中即緩存穿透到數據庫,從數據庫查詢數據而後回寫到緩存中,最後返回數據給客戶端。markdown

(2)寫請求常見流程架構

 Cache aside 寫請求
Cache aside 寫請求

首先更新數據庫,而後從緩存中刪除該數據。併發

看了寫請求的圖以後,有些同窗可能要問了:爲何要刪除緩存,直接更新不就好了?這裏涉及到幾個坑,咱們一步一步踩下去。ide

Cache aside踩坑

Cache aside策略若是用錯就會遇到深坑,下面咱們來逐個踩。oop

踩坑一:先更新數據庫,再更新緩存

若是同時有兩個寫請求須要更新數據,每一個寫請求都先更新數據庫再更新緩存,在併發場景可能會出現數據不一致的狀況。

先更新數據庫,再更新緩存
先更新數據庫,再更新緩存

如上圖的執行過程:

(1)寫請求1更新數據庫,將 age 字段更新爲18;

(2)寫請求2更新數據庫,將 age 字段更新爲20;

(3)寫請求2更新緩存,緩存 age 設置爲20;

(4)寫請求1更新緩存,緩存 age 設置爲18;

執行完預期結果是數據庫 age 爲20,緩存 age 爲20,結果緩存 age爲18,這就形成了緩存數據不是最新的,出現了髒數據。

踩坑二:先刪緩存,再更新數據庫

若是寫請求的處理流程是先刪緩存再更新數據庫,在一個讀請求和一個寫請求併發場景下可能會出現數據不一致狀況。

先刪緩存,再更新數據庫
先刪緩存,再更新數據庫

如上圖的執行過程:

(1)寫請求刪除緩存數據;

(2)讀請求查詢緩存未擊中(Hit Miss),緊接着查詢數據庫,將返回的數據回寫到緩存中;

(3)寫請求更新數據庫。

整個流程下來發現數據庫中age爲20,緩存中age爲18,緩存和數據庫數據不一致,緩存出現了髒數據。

踩坑三:先更新數據庫,再刪除緩存

在實際的系統中針對寫請求仍是推薦先更新數據庫再刪除緩存,可是在理論上仍是存在問題,如下面這個例子說明。

先更新數據庫,再刪除緩存
先更新數據庫,再刪除緩存

如上圖的執行過程:

(1)讀請求先查詢緩存,緩存未擊中,查詢數據庫返回數據;

(2)寫請求更新數據庫,刪除緩存;

(3)讀請求回寫緩存;

整個流程操做下來發現數據庫age爲20緩存age爲18,即數據庫與緩存不一致,致使應用程序從緩存中讀到的數據都爲舊數據。

但咱們仔細想一下,上述問題發生的機率其實很是低,由於一般數據庫更新操做比內存操做耗時多出幾個數量級,上圖中最後一步回寫緩存(set age 18)速度很是快,一般會在更新數據庫以前完成。

若是這種極端場景出現了怎麼辦?咱們得想一個兜底的辦法:緩存數據設置過時時間。一般在系統中是能夠容許少許的數據短期不一致的場景出現。

Read through

在 Cache Aside 更新模式中,應用代碼須要維護兩個數據源頭:一個是緩存,一個是數據庫。而在 Read-Through 策略下,應用程序無需管理緩存和數據庫,只須要將數據庫的同步委託給緩存提供程序 Cache Provider 便可。全部數據交互都是經過抽象緩存層完成的。

Read-Through流程
Read-Through流程

如上圖,應用程序只須要與Cache Provider交互,不用關心是從緩存取仍是數據庫。

在進行大量讀取時,Read-Through 能夠減小數據源上的負載,也對緩存服務的故障具有必定的彈性。若是緩存服務掛了,則緩存提供程序仍然能夠經過直接轉到數據源來進行操做。

Read-Through 適用於屢次請求相同數據的場景,這與 Cache-Aside 策略很是類似,可是兩者仍是存在一些差異,這裏再次強調一下:

  • 在 Cache-Aside 中,應用程序負責從數據源中獲取數據並更新到緩存。
  • 在 Read-Through 中,此邏輯一般是由獨立的緩存提供程序(Cache Provider)支持。

Write through

Write-Through 策略下,當發生數據更新(Write)時,緩存提供程序 Cache Provider 負責更新底層數據源和緩存。

緩存與數據源保持一致,而且寫入時始終經過抽象緩存層到達數據源。

Cache Provider相似一個代理的做用。

Write-Through流程
Write-Through流程

Write behind

Write behind在一些地方也被成爲Write back, 簡單理解就是:應用程序更新數據時只更新緩存, Cache Provider每隔一段時間將數據刷新到數據庫中。說白了就是延遲寫入

Write behind流程
Write behind流程

如上圖,應用程序更新兩個數據,Cache Provider 會當即寫入緩存中,可是隔一段時間纔會批量寫入數據庫中。

這種方式有優勢也有缺點:

  • 優勢是數據寫入速度很是快,適用於頻繁寫的場景。

  • 缺點是緩存和數據庫不是強一致性,對一致性要求高的系統慎用。

總結一下

學了這麼多,相信你們對緩存更新的策略都已經有了清晰的認識。最後稍稍總結一下。

緩存更新的策略主要分爲三種:

  • Cache aside
  • Read/Write through
  • Write behind

Cache aside 一般會先更新數據庫,而後再刪除緩存,爲了兜底一般還會將數據設置緩存時間。

Read/Write through 通常是由一個 Cache Provider 對外提供讀寫操做,應用程序不用感知操做的是緩存仍是數據庫。

Write behind簡單理解就是延遲寫入,Cache Provider 每隔一段時間會批量輸入數據庫,優勢是應用程序寫入速度很是快。

好了,今天先到這裏了,你們學會了嗎?

-- END --

不要白嫖,點個贊咯,每一張圖都是精心畫的~

做者簡介: ☕讀過幾年書:華中科技大學碩士畢業;
😂浪過幾個大廠:華爲、網易、百度……
😘一直堅信技術能改變生活,願保持初心,加油技術人!

微信搜索公衆號【愛笑的架構師】,關注這個對技術和生活有追求的技術人。

最後推薦一個寶藏開源項目,github.com/smileArchit… 
JavaMap是Java知識地圖,讓開發者學習不迷路!Java學習請認準JavaMap。
JAVA核心知識點整理(283頁,超級詳細)免費領取。

🏆 技術專題第八期 | 聊聊緩存的妙用和問題

相關文章
相關標籤/搜索