引言:在某一天面試的時候,小 x 被問到 Redis 三種緩存讀寫的策略,他懵了,原因是簡歷上明明是寫著熟悉 Redis,因此面試官可以隨意向任何一個方向進行開火,大家要註意從小點切入,除非自己是完全能夠掌握這門技術的,本文將帶你去了解三種常用的緩存讀寫策略的優缺點和使用場景。
題目
Redis 三種高效緩存讀寫策略你了解嗎?
推薦解析
旁路緩存模式(Cache Aside Pattern)
旁路緩存是最常見的緩存讀寫模式,適用於讀多寫少的使用經常。伺服端以資料庫比如 MySQL 為主,Redis 為輔,進行儲存。
寫操作流程
1)先更新資料庫
2)刪除 Redis 中的緩存
讀操作流程
1)嘗試從緩存中讀取數據,讀取到數據就直接返回
2)緩存中讀取不到,從資料庫中讀取數據
3)讀取完畢後,將數據放入緩存
緩存不一致可能的場景(先刪後更)
假如先刪除緩存,再更新資料庫,大機率會造成緩存不一致。執行緒 1 把 Redis 中 x 數據刪除,此時執行緒 2 發現緩存中沒有數據,從資料庫讀取,而執行緒以此時又把資料庫中的 x 數據更新,因此執行緒 2 讀取到的就是舊數據,造成了緩存不一致的情況。
緩存不一致發生機率小
被推薦的作法,就是上文講過的,先更新資料庫,再刪除緩存。
可能不一致的場景如下
1)緩存中 X(數據) 不存在(資料庫 X = 1) 2)執行緒 1 讀取資料庫,得到舊值(X = 1) 3)執行緒 2 更新資料庫(X = 2) 4)執行緒 2 刪除緩存 5)執行緒 1 將舊值寫入緩存(X = 1) 6)最終 X 的值在緩存中是 1(舊值),在資料庫中是 2(新值),也發生不一致。
此場景需要滿足:1)緩存失效 2) 讀寫請求同步對一個數據進行並行操作 3)更新資料庫+刪除緩存的時間大於讀取和寫入緩存的時間,也就是說寫操作時間大於度操作時間,因為緩存這塊可以不計入,理論發生機率是很小的。
旁路緩存優缺點
優點
1)提高數據存取速度
2)減少主記憶體存取
3)提高並行性
缺點
1)存在緩存資料庫不一致情況
2)首次請求數據一定不在緩存(可以緩存預熱結合定時任務)
3)寫操作頻繁會導致緩存被頻繁刪除,影響緩存命中率。(可以加分布式鎖,保證更新資料庫同時更新緩存。或者直接設定一個較短的過期時間)
旁路緩存範例程式碼
import java.util.HashMap;
import java.util.Map;
public classCacheAsideExample{
// 模擬緩存
privatestatic Map<String, String> cache = new HashMap<>();
// 模擬資料庫或資料來源
privatestatic Map<String, String> dataSource = new HashMap<>();
// 從緩存中獲取數據
publicstatic String getDataFromCache(String key){
return cache.get(key);
}
// 從資料來源中獲取數據
publicstatic String getDataFromDataSource(String key){
return dataSource.get(key);
}
// 將數據存入緩存
publicstaticvoidputDataIntoCache(String key, String value){
cache.put(key, value);
}
// 刪除緩存中的數據
publicstaticvoiddeleteDataFromCache(String key){
cache.remove(key);
}
// 從資料來源中載入數據,並存入緩存
publicstatic String loadData(String key){
String data = getDataFromDataSource(key);
if (data != null) {
putDataIntoCache(key, data);
}
return data;
}
publicstaticvoidmain(String[] args){
// 設定資料來源
dataSource.put("key1", "value1");
dataSource.put("key2", "value2");
// 從緩存中獲取數據,如果不存在則從資料來源中載入
String data1 = getDataFromCache("key1");
if (data1 == null) {
data1 = loadData("key1");
}
System.out.println("Data1: " + data1);
// 從緩存中獲取數據,如果不存在則從資料來源中載入
String data2 = getDataFromCache("key2");
if (data2 == null) {
data2 = loadData("key2");
}
System.out.println("Data2: " + data2);
// 刪除緩存中的數據
deleteDataFromCache("key1");
// 從緩存中獲取數據,如果不存在則從資料來源中載入
String data3 = getDataFromCache("key1");
if (data3 == null) {
data3 = loadData("key1");
}
System.out.println("Data3: " + data3);
}
}
讀寫穿透(Read/Write Through Pattern)
讀寫穿透策略將 Redis/Memcached 視為數據儲存的主要地方,也就是說將緩存充當原本的資料庫,利用 Cache 服務負責將數據讀取並寫入資料庫(MySQL、Oracle等)。
寫操作流程
1)先查詢緩存,緩存不存在,更新資料庫
2)緩存存在,先更新緩存,利用 Cache 服務同步更新資料庫。
讀操作流程
1)從緩存讀取數據,讀取到返回
2)緩存讀取不到,從資料庫載入後寫入緩存並返回。
和旁路緩存相反,讀寫穿透,主緩存從資料庫。
異步緩存寫入(Write Behind Pattern)
只更新緩存,不利用 Cache 服務更新資料庫,可以利用訊息佇列,先存放要消費的資訊,然後可以異步批次的更新資料庫,一般不使用,但資料庫的緩沖池機制是這種策略的一個實作,
適用場景:數據經常變化,一致性要求不高(可以延時同步),比如 PV、UV、點贊量。
其他補充
魚聰明 AI 的回答:
魚聰明 AI 地址:https://www.yucongming.com/
1) 旁路緩存(Cache Aside)
1.1)優點
簡單易實作,適用於小規模系統。
緩存數據不會過期,不會出現緩存雪崩。
1.2)缺點
數據一致性問題,需要應用程式主動更新緩存。
緩存數據可能過期,導致緩存擊穿。
1.3)使用場景
適用於讀多寫少的場景。
數據更新頻率不高,對數據即時性要求不高的場景。
2) 讀寫穿透(Cache Through)
2.1)優點
數據一致性較好,不會出現數據不一致的情況。
緩存數據不會過期,不會出現緩存雪崩。
2.2)缺點
需要保證資料來源的可靠性和效能。
對於大規模系統,可能增加資料來源的壓力。
2.3)使用場景
適用於資料來源更新頻率高,對數據即時性要求高的場景。
資料來源具有較好的效能和可靠性。
3) 異步緩存寫入(Write Behind)
3.1)優點
減少對資料來源的頻繁寫入,提高效能。
可以緩解瞬時寫入壓力,提高系統穩定性。
3.2)缺點
數據一致性可能受影響,存在一定的數據遺失風險。
需要額外的機制來處理數據更新失敗的情況。
3.3)使用場景
適用於寫入頻率高,對數據即時性要求不高的場景。
對數據遺失一定容忍度的場景。
在實際套用中,根據系統的特點和需求,可以選擇合適的緩存讀寫策略來提高系統效能和穩定性。
歡迎交流
在閱讀完本篇文章後,你應該對 Redis 的三種緩存讀寫策略有了一定了解,一般采用第一個策略進行讀寫,其他兩種策略了解即可,在文末有三個問題將會檢驗本章的學習,歡迎在評論區發表意見。
1)旁路緩存策略中,如何解決緩存數據過期和緩存擊穿的問題?
2)讀寫穿透策略中,如何確保資料來源的可靠性和效能,以及如何處理資料來源故障的情況?
3)在實際套用中,如何選擇合適的緩存讀寫策略,考慮到系統的特點和需求?
點燃求職熱情!每周持續更新,海量面試題等你挑戰!趕緊關註面試鴨公眾號,輕松備戰春招和暑期實習!