緩存七大經典問題

目錄

一、緩存失效

二、緩存穿透

三、緩存雪崩

四、數據不一致

五、數據併發競爭

六、Hot key

七、Big key


一、緩存失效

問題描述

一次性緩存大量數據,設置了相同過期時間,同時失效。

解決方案

即相同業務數據寫緩存時,在基礎過期時間之上,再加一個隨機的過期時間,讓數據在未來一段時間內慢慢過期,避免瞬時全部過期,對DB造成過大壓力。

過期時間 = base 時間 + 隨機時間

二、緩存穿透

問題描述

有特殊訪客在查詢一個不存在的 key,導致每次查詢都會穿透到 DB。

解決方案

1、查詢這些不存在的數據時,第一次查 DB,雖然沒查到結果返回 NULL,仍然記錄這個 key 到緩存,只是這個 key 對應的 value 是一個特殊設置的值。

注:如果特殊訪客持續訪問大量的不存在的 key,這些 key 即便只存一個簡單的默認值,也會佔用大量的緩存空間,導致正常 key 的命中率下降。所以進一步的改進措施是,對這些不存在的 key 只存較短的時間,讓它們儘快過期;或者將這些不存在的 key 存在一個獨立的公共緩存,從緩存查找時,先查正常的緩存組件,如果 miss,則查一下公共的非法 key 的緩存,如果後者命中,直接返回,否則穿透 DB,如果查出來是空,則回種到非法 key 緩存,否則回種到正常緩存。

2、構建一個 BloomFilter 緩存過濾器,記錄全量數據,這樣訪問數據時,可以直接通過 BloomFilter 判斷這個 key 是否存在,如果不存在直接返回即可,根本無需查緩存和 DB。

注:BloomFilter 要緩存全量的 key,這就要求全量的 key 數量不大,10億 條數據以內最佳,因爲 10億 條數據大概要佔用 1.2GB 的內存。也可以用 BloomFilter 緩存非法 key,每次發現一個 key 是不存在的非法 key,就記錄到 BloomFilter 中,這種記錄方案,會導致 BloomFilter 存儲的 key 持續高速增長,爲了避免記錄 key 太多而導致誤判率增大,需要定期清零處理。

三、緩存雪崩

問題描述

緩存雪崩是指部分緩存節點不可用,導致整個緩存體系甚至甚至服務系統不可用的情況。

解決方案

1、對業務 DB 的訪問增加讀寫開關,當發現 DB 請求變慢、阻塞,慢請求超過閾值時,就會關閉讀開關,部分或所有讀 DB 的請求進行 failfast 立即返回,待 DB 恢復後再打開讀開關。

2、對緩存增加多個副本,緩存異常或請求 miss 後,再讀取其他緩存副本,而且多個緩存副本儘量部署在不同機架,從而確保在任何情況下,緩存系統都會正常對外提供服務。

3、對緩存體系進行實時監控,當請求訪問的慢速比超過閾值時,及時報警,通過機器替換、服務替換進行及時恢復;也可以通過各種自動故障轉移策略,自動關閉異常接口、停止邊緣服務、停止部分非核心功能措施,確保在極端場景下,核心功能的正常運行。

四、數據不一致

問題描述

同一份數據,可能會同時存在 DB 和緩存之中。那就有可能發生,DB 和緩存的數據不一致。如果緩存有多個副本,多個緩存副本里的數據也可能會發生不一致現象。

解決方案

1、cache 更新失敗後,可以進行重試,如果重試失敗,則將失敗的 key 寫入隊列機服務,待緩存訪問恢復後,將這些 key 從緩存刪除。這些 key 在再次被查詢時,重新從 DB 加載,從而保證數據的一致性。

2、緩存時間適當調短,讓緩存數據及早過期後,然後從 DB 重新加載,確保數據的最終一致性。

3、不採用 rehash 漂移策略,而採用緩存分層策略,儘量避免髒數據產生。

五、數據併發競爭

問題描述

主要是由於多個進程/線程中,有大量併發請求獲取相同的數據,而這個數據 key 因爲正好過期、被剔除等各種原因在緩存中不存在,這些進程/線程之間沒有任何協調,然後一起併發查詢 DB,請求那個相同的 key,最終導致 DB 壓力大增。

解決方案

1、使用全局鎖。即當緩存請求 miss 後,先嚐試加全局鎖,只有加全局鎖成功的線程,纔可以到 DB 去加載數據。其他進程/線程在讀取緩存數據 miss 時,如果發現這個 key 有全局鎖,就進行等待,待之前的線程將數據從 DB 回種到緩存後,再從緩存獲取。

2、對緩存數據保持多個備份,即便其中一個備份中的數據過期或被剔除了,還可以訪問其他備份,從而減少數據併發競爭的情況。

六、Hot key

問題描述

對於大多數互聯網系統,數據是分冷熱的。比如最近的新聞、新發表的微博被訪問的頻率最高,而比較久遠的之前的新聞、微博被訪問的頻率就會小很多。而在突發事件發生時,大量用戶同時去訪問這個突發熱點信息,訪問這個 Hot key,這個突發熱點信息所在的緩存節點就很容易出現過載和卡頓現象,甚至會被 Crash。

解決方案

要解決這種極熱 key 的問題,首先要找出這些 Hot key 來。對於重要節假日、線上促銷活動、集中推送這些提前已知的事情,可以提前評估出可能的熱 key 來。而對於突發事件,無法提前評估,可以通過 Spark,對應流任務進行實時分析,及時發現新發布的熱點 key。而對於之前已發出的事情,逐步發酵成爲熱 key 的,則可以通過 Hadoop 對批處理任務離線計算,找出最近歷史數據中的高頻熱 key。

找到熱 key 後,就有很多解決辦法了。首先可以將這些熱 key 進行分散處理,比如一個熱 key 名字叫 hotkey,可以被分散爲 hotkey#1、hotkey#2、hotkey#3,……hotkey#n,這 n 個 key 分散存在多個緩存節點,然後 client 端請求時,隨機訪問其中某個後綴的 hotkey,這樣就可以把熱 key 的請求打散,避免一個緩存節點過載。

其次,也可以 key 的名字不變,對緩存提前進行多副本+多級結合的緩存架構設計。

再次,如果熱 key 較多,還可以通過監控體系對緩存的 SLA 實時監控,通過快速擴容來減少熱 key 的衝擊。

最後,業務端還可以使用本地緩存,將這些熱 key 記錄在本地緩存,來減少對遠程緩存的衝擊。

七、Big key

問題描述

大 key,是指在緩存訪問時,部分 Key 的 Value 過大,讀寫、加載易超時的現象。

解決方案

1、果數據存在 Mc 中,可以設計一個緩存閾值,當 value 的長度超過閾值,則對內容啓用壓縮,讓 KV 儘量保持小的 size,其次評估大 key 所佔的比例,在 Mc 啓動之初,就立即預寫足夠數據的大 key,讓 Mc 預先分配足夠多的 trunk size 較大的 slab。確保後面系統運行時,大 key 有足夠的空間來進行緩存。 

2、如果數據存在 Redis 中,比如業務數據存 set 格式,大 key 對應的 set 結構有幾千幾萬個元素,這種寫入 Redis 時會消耗很長的時間,導致 Redis 卡頓。此時,可以擴展新的數據結構,同時讓 client 在這些大 key 寫緩存之前,進行序列化構建,然後通過 restore 一次性寫入

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章