經典面試題:一文了解常見的緩存問題
在面試過程中,面試官的桌子上擺放著很多高頻的面試題,能否順利回答決定了你面試通過的概率。其中緩存問題就是其中的一份,可以說掌握緩存問題及解決方法是面試前必須準備的內容。那么緩存有什么典型的問題,出現的原因是什么,又該如何解決呢?本文,來為你一一詳細介紹。
緩存問題有哪些?
緩存雖然能提升性能,但也會帶來一些問題。緩存問題有很多,其中經典的緩存問題如下圖所示:
1. 緩存雪崩
問題描述:緩存服務宕機,導致所有請求直接訪問數據庫,引發數據庫壓力激增甚至崩潰。
解決方法:
- 集群化部署緩存(如Redis Cluster),實現高可用;
- 使用熔斷降級機制,限制數據庫訪問量;
- 讀寫分離;
- 使用本地緩存;
- 對緩存體系進行實時監控,當請求訪問的慢速比超過閥值時,及時報警,通過機器替換、服務替換進行及時恢復;也可以通過各種自動故障轉移策略,自動關閉異常接口、停止邊緣服務、停止部分非核心功能措施,確保在極端場景下,核心功能的正常運行。
2. 緩存失效
問題描述:大量緩存數據同時過期,導致所有請求直接訪問數據庫,引發數據庫壓力激增甚至崩潰。
解決方法:設置隨機過期時間,避免同時失效。使用公式:過期時間 = base 時間 + 隨機時間。
3. 緩存穿透
問題描述:頻繁查詢不存在的數據(如惡意攻擊),緩存和數據庫均無法命中,導致無效請求穿透到數據庫。
解決方法:
- 布隆過濾器(Bloom Filter): 構建一個 BloomFilter 緩存過濾器,記錄全量數據,這樣訪問數據時,可以直接通過 BloomFilter 判斷這個 key 是否存在,如果不存在直接返回即可,根本無需查緩存和 DB。但是BloomFilter 要緩存全量的 key,這就要求全量的 key 數量不大,10億條數據以內最佳,因為 10億 條數據大概要占用 1.2GB 的內存。也可以用 BloomFilter 緩存非法 key,每次發現一個 key 是不存在的非法 key,就記錄到 BloomFilter 中,這種記錄方案,會導致 BloomFilter 存儲的 key 持續高速增長,為了避免記錄 key 太多而導致誤判率增大,需要定期清零處理;
- 緩存空值(Null Object): 為不存在的 Key 設置短時間緩存,避免重復查詢數據庫。
4. 緩存擊穿
問題描述:某個熱點Key突然過期,大量并發請求直接訪問數據庫,導致瞬時壓力過大。
解決方法:
- 永久緩存: 針對基本不會發生更新的場景,可以把 key 設置為永不過期,讓 key 常駐緩存;定期緩存:針對需要頻繁更新的場景,可以使用額外的補償程序來定時刷新緩存或者延長 key 的實效時間;
- 分布式鎖: 針對偶爾需要更新的場景,可以對請求代碼使用分布式互斥鎖,使得少部分直接請求數據庫后更新緩存,而剩余的其他請求直接使用新緩存即可,或者采用本地互斥鎖保證僅有少量請求能夠更新緩存,其余請求訪問新緩存。
5. 緩存與數據庫一致性
問題描述:緩存與數據庫數據不一致,常見于更新操作時,比如更新 DB 后,寫緩存失敗,從而導致緩存中存的是老數據。
解決方式:
- 刪除 Key: 寫入/更新的時候,先刪除緩存中的 Key,再更新數據庫;
- 訂閱數據庫Binlog: 通過監聽數據庫變更同步更新緩存(如Canal工具);
- 最終一致性容忍: 根據業務場景接受短暫不一致。
6. 緩存預熱
問題描述:系統啟動時緩存為空,大量請求直接訪問數據庫導致冷啟動壓力。
解決方式:提前加載熱點數據到緩存(如統計分析高頻訪問的Key)。
7. 緩存淘汰策略
問題描述:緩存空間有限時,如何選擇淘汰哪些數據以騰出空間。
解決方式:
- LRU(Least Recently Used): 淘汰最近最少使用的數據;
- LFU(Least Frequently Used): 淘汰訪問頻率最低的數據;
- TTL(Time To Live):基于過期時間淘汰。
8. 緩存污染
問題描述:緩存中存儲了低頻訪問的數據,擠占了熱點數據的空間。
解決方式:
優化緩存淘汰策略(如結合LRU和LFU);
定期清理非熱點數據。
9. 熱點 Key
問題描述:某些業務在某一瞬間或某一時間段內可能會成為熱點業務,熱點業務的數據可能會產生熱點key,比如微博上熱榜數據。
解決方式:
- 找到對應的熱點 key,將這些熱 key 進行分散處理,比如一個熱 key 名字叫 hotkey,可以被分散為 hotkey#1、hotkey#2、hotkey#3,……hotkey#n,這 n 個 key 分散存在多個緩存節點,然后 client 端請求時,隨機訪問其中某個后綴的 hotkey,這樣就可以把熱 key 的請求打散,避免一個緩存節點過載;
- 也可以 key 的名字不變,對緩存提前進行多副本+多級結合的緩存架構設計。再次,如果熱 key 較多,還可以通過監控體系對緩存的 SLA 實時監控,通過快速擴容來減少熱 key 的沖擊。最后,業務端還可以使用本地緩存,將這些熱 key 記錄在本地緩存,來減少對遠程緩存的沖擊。
10. 大 Key
問題描述:緩存中某些 key 的 value 的值過大,導致寫操作超時、加載速度緩慢等問題。
解決方式:
- 如果數據存在 MC 中,可以設計一個緩存閥值,當 value 的長度超過閥值,則對內容啟用壓縮,讓 KV 盡量保持小的 size,其次評估大 key 所占的比例,在 Mc 啟動之初,就立即預寫足夠數據的大 key,讓 MC 預先分配足夠多的 trunk size 較大的 slab。確保后面系統運行時,大 key 有足夠的空間來進行緩存;
- 如果數據存在 Redis 中,比如業務數據存 set 格式,大 key 對應的 set 結構有幾千幾萬個元素,這種寫入 Redis 時會消耗很長的時間,導致 Redis 卡頓。此時,可以擴展新的數據結構,同時讓 client 在這些大 key 寫緩存之前,進行序列化構建,然后通過 restore 一次性寫入;
- 將大 key 分拆為多個 key,盡量減少大 key 的存在。同時由于大 key 一旦穿透到 DB,加載耗時很大,所以可以對這些大 key 進行特殊照顧,比如設置較長的過期時間,比如緩存內部在淘汰 key 時,同等條件下,盡量不淘汰這些大 key。