本文 github.com/smileArchit… 已收錄。
JavaMap是Java知識地圖,旨在讓開發者學習不迷路!Java學習請認準JavaMap。git
在大型系統中,爲了減小數據庫壓力一般會引入緩存機制,一旦引入緩存又很容易形成緩存和數據庫數據不一致,致使用戶看到的是舊數據。github
爲了減小數據不一致的狀況,更新緩存和數據庫的機制顯得尤其重要,接下來帶領你們踩踩坑。數據庫
Cache aside
也就是旁路緩存
,是比較經常使用的緩存策略。緩存
(1)讀請求
常見流程微信
應用首先會判斷緩存是否有該數據,緩存命中直接返回數據,緩存未命中即緩存穿透到數據庫,從數據庫查詢數據而後回寫到緩存中,最後返回數據給客戶端。markdown
(2)寫請求
常見流程架構
首先更新數據庫,而後從緩存中刪除該數據。併發
看了寫請求的圖以後,有些同窗可能要問了:爲何要刪除緩存,直接更新不就好了?這裏涉及到幾個坑,咱們一步一步踩下去。ide
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)速度很是快,一般會在更新數據庫以前完成。
若是這種極端場景出現了怎麼辦?咱們得想一個兜底的辦法:緩存數據設置過時時間
。一般在系統中是能夠容許少許的數據短期不一致的場景出現。
在 Cache Aside 更新模式中,應用代碼須要維護兩個數據源頭:一個是緩存,一個是數據庫。而在 Read-Through
策略下,應用程序無需管理緩存和數據庫,只須要將數據庫的同步委託給緩存提供程序 Cache Provider
便可。全部數據交互都是經過抽象緩存層
完成的。
如上圖,應用程序只須要與Cache Provider
交互,不用關心是從緩存取仍是數據庫。
在進行大量讀取時,Read-Through
能夠減小數據源上的負載,也對緩存服務的故障具有必定的彈性。若是緩存服務掛了,則緩存提供程序仍然能夠經過直接轉到數據源來進行操做。
Read-Through 適用於屢次請求相同數據的場景
,這與 Cache-Aside 策略很是類似,可是兩者仍是存在一些差異,這裏再次強調一下:
Write-Through
策略下,當發生數據更新(Write)時,緩存提供程序 Cache Provider
負責更新底層數據源和緩存。
緩存與數據源保持一致,而且寫入時始終經過抽象緩存層
到達數據源。
Cache Provider
相似一個代理的做用。
Write behind
在一些地方也被成爲Write back
, 簡單理解就是:應用程序更新數據時只更新緩存, Cache Provider
每隔一段時間將數據刷新到數據庫中。說白了就是延遲寫入
。
如上圖,應用程序更新兩個數據,Cache Provider 會當即寫入緩存中,可是隔一段時間纔會批量寫入數據庫中。
這種方式有優勢也有缺點:
優勢
是數據寫入速度很是快,適用於頻繁寫的場景。
缺點
是緩存和數據庫不是強一致性,對一致性要求高的系統慎用。
學了這麼多,相信你們對緩存更新的策略都已經有了清晰的認識。最後稍稍總結一下。
緩存更新的策略主要分爲三種:
Cache aside 一般會先更新數據庫,而後再刪除緩存,爲了兜底一般還會將數據設置緩存時間。
Read/Write through 通常是由一個 Cache Provider 對外提供讀寫操做,應用程序不用感知操做的是緩存仍是數據庫。
Write behind簡單理解就是延遲寫入,Cache Provider 每隔一段時間會批量輸入數據庫,優勢是應用程序寫入速度很是快。
好了,今天先到這裏了,你們學會了嗎?
-- END --
不要白嫖,點個贊咯,每一張圖都是精心畫的~
做者簡介: ☕讀過幾年書:華中科技大學碩士畢業;
😂浪過幾個大廠:華爲、網易、百度……
😘一直堅信技術能改變生活,願保持初心,加油技術人!微信搜索公衆號【愛笑的架構師】,關注這個對技術和生活有追求的技術人。
最後推薦一個寶藏開源項目,github.com/smileArchit…
JavaMap是Java知識地圖,讓開發者學習不迷路!Java學習請認準JavaMap。
JAVA核心知識點整理(283頁,超級詳細)免費領取。