先闡明一下 MySQL 和 Redis 的關系:
MySQL
是資料庫,用來持久化數據,一定程度上保證數據的可靠性;
Redis 是用來當緩存,用來提升數據存取的效能。
關於如何保證 MySQL 和 Redis 中的數據一致(即緩存一致性問題),這是一個非常經典的問題。
使用過緩存的人都應該知道,在實際套用場景中,要想即時刻保證緩存和資料庫中的數據一樣,很難做到。
基本上都是盡可能讓他們的數據在絕大部份時間內保持一致,並保證最終是一致的。
1、緩存不一致是如何產生的
如果數據一直沒有變更,那麽就不會出現緩存不一致的問題。
通常緩存不一致是發生在數據有變更的時候。因為每次數據變更你需要同時操作資料庫和緩存,而他們又屬於不同的系統,無法做到同時操作成功或失敗,總會有一個時間差。在並行讀寫的時候可能就會出現緩存不一致的問題(理論上透過分布式事務可以保證這一點,不過實際上基本上很少有人這麽做)。
雖然沒辦法在數據有變更時,保證緩存和資料庫強一致,但對緩存的更新還是有一定設計方法的,遵循這些設計方法,能夠讓這個不一致的影響時間和影響範圍最小化。
2、緩存更新的幾種設計
緩存更新的設計方法大概有以下四種:
先刪除緩存,再更新資料庫(這種方法在並行下最容易出現長時間的臟數據,不可取)
先更新資料庫,刪除緩存(Cache Aside Pattern)
只更新緩存,由緩存自己同步更新資料庫(Read/Write Through Pattern)
只更新緩存,由緩存自己異步更新資料庫(Write Behind Cache Pattern)
接下來詳細介紹一些這四種設計方法
2.1 先刪除緩存,再更新資料庫
這種方法在並行讀寫的情況下容易出現緩存不一致的問題
如上圖所示,其可能的執行流程順序為:
客戶端1 觸發更新數據A的邏輯
客戶端2 觸發查詢數據A的邏輯
客戶端1 刪除緩存中數據A
客戶端2 查詢緩存中數據A,未命中
客戶端2 從資料庫查詢數據A,並更新到緩存中
客戶端1 更新資料庫中數據A
可見,最後緩存中的數據 A 跟資料庫中的數據 A 是不一致的,緩存中的數據A是舊的臟數據。
因此一般不建議使用這種方式。
2.2 先更新資料庫,再讓緩存失效
這種方法在並行讀寫的情況下,也可能會出現短暫緩存不一致的問題
如上圖所示,其可能執行的流程順序為:
客戶端1 觸發更新數據A的邏輯
客戶端2 觸發查詢數據A的邏輯
客戶端3 觸發查詢數據A的邏輯
客戶端1 更新資料庫中數據A
客戶端2 查詢緩存中數據A,命中返回(舊數據)
客戶端1 讓緩存中數據A失效
客戶端3 查詢緩存中數據A,未命中
客戶端3 查詢資料庫中數據A,並更新到緩存中
可見,最後緩存中的數據A和資料庫中的數據 A 是一致的,理論上可能會出現一小段時間數據不一致,不過這種機率也比較低,大部份的業務也不會有太大的問題。
2.3 只更新緩存,由緩存自己同步更新資料庫(Read/Write Through Pattern)
這種方法相當於是業務只更新緩存,再由緩存去同步更新資料庫。一個Write Through的 例子如下:
如上圖所示,其可能執行的流程順序為:
客戶端1 觸發更新數據 A 的邏輯
客戶端2 觸發查詢數據 A 的邏輯
客戶端1 更新緩存中數據 A,緩存同步更新資料庫中數據 A,再返回結果
客戶端2 查詢緩存中數據 A,命中返回
Read Through 和 WriteThrough 的流程類似,只是在客戶端查詢數據A時,如果緩存中數據A失效了(過期或被驅逐淘汰),則緩存會同步去資料庫中查詢數據A,並緩存起來,再返回給客戶端。
這種方式緩存不一致的機率極低,只不過需要對緩存進行專門的改造。
2.4 只更新緩存,由緩存自己異步更新資料庫(Write Behind Cache Pattern)
這種方式性詳單於是業務只操作更新緩存,再由緩存異步去更新資料庫,例如:
如上圖所示,其可能的執行流程順序為:
客戶端1 觸發更新數據 A 的邏輯
客戶端2 觸發查詢數據 A 的邏輯
客戶端1 更新緩存中的數據 A,返回
客戶端2 查詢緩存中的數據 A,命中返回
緩存異步更新數據 A 到資料庫中
這種方式的優勢是讀寫的效能都非常好,基本上只要操作完記憶體後就返回給客戶端了,但是其是非強一致性,存在遺失數據的情況。
如果在緩存異步將數據更新到資料庫中時,緩存服務掛了,此時未更新到資料庫中的數據就遺失了。
總結
上面講到的幾種緩存更新的設計方式,都是前人總結出來的經驗,這些方式或多或少都有一些弊端,並不完美,實際上也很難有完美的設計。大家在做系統設計的時候,也不要去追求完美,要有一些取舍,找到一種最適合自己業務場景的方式就行。
來源:developer.jdcloud.com/article/2776
>>
END
精品資料,超贊福利,免費領
微信掃碼/長按辨識 添加【技術交流群】
群內每天分享精品學習資料
最近開發整理了一個用於速刷面試題的小程式;其中收錄了上千道常見面試題及答案(包含基礎、並行、JVM、MySQL、Redis、Spring、SpringMVC、SpringBoot、SpringCloud、訊息佇列等多個型別),歡迎您的使用。
👇👇
👇點選"閱讀原文",獲取更多資料(持續更新中)