那天我在一家互聯網大廠面試,被問了一個看似簡單、實則殺傷力極強的問題:
“小米,假如MySQL裏有2000萬條數據,Redis裏只能存20萬條,你該怎麼保證Redis中的數據都是熱點數據?”
當場我笑出了聲,心想這題是“送命題”吧!但笑歸笑,能不能答好,真能看出你是不是一個“實戰派”的程序員。
今天這篇文章,就帶你把這道題拆開、揉碎、講透。
故事從一個“假想項目”開始
那天,面試官給了我一個場景:
“我們公司做電商系統,商品表有2000萬條數據。商品詳情頁訪問量巨大,但Redis內存有限,只能放20萬條。
請你設計一個機制,保證Redis中的數據始終是最熱的那部分。”
我當時想起了一個詞——冷熱分層緩存。
於是我就從用户行為開始分析。
從用户行為説起:熱點數據的本質
在實際系統中,數據訪問有一個著名規律:
二八法則(80/20原則) —— 20%的數據,承載了80%的訪問量。
也就是説,2000萬條商品裏,可能有幾十萬條才是真正被頻繁訪問的“熱數據”。
這些熱數據有幾個特徵:
- 高訪問頻率:比如熱門商品、活動商品。
- 時間敏感性強:比如“秒殺商品”、“熱榜”。
- 生命週期短:熱點會變動,今天火的明天可能涼。
明白了這些特徵,我們才能思考“如何動態維護Redis中的20萬條”。
錯誤的開始:最容易掉坑的兩個思路
在我剛工作那幾年,也遇到過類似問題。那時我天真地以為,只要在Redis裏設置個LRU(最近最少使用)策略就行。
事實證明:
想靠Redis自己搞定熱點維護,基本等於讓倉庫管理員“憑感覺”去挑暢銷品。
問題有三:
- Redis LRU是局部淘汰:它只在達到內存上限時才淘汰,不是全局最優。
- 訪問波動太快:熱點可能幾分鐘就變了,Redis反應太慢。
- 熱點穿透/擊穿/雪崩問題:一旦熱點沒命中,數據庫就遭殃。
所以,僅靠Redis配置不夠,我們得有一套完整的策略體系。
正確的思路:分層 + 動態 + 指標驅動
我當時的回答思路是這樣的(後來面試官很滿意):
“我會設計一個冷熱分層緩存架構,配合訪問統計與異步更新機制,讓Redis自動只保存真正的熱點數據。”
具體拆解成三層:
第1層:讀請求分層緩存架構
先從讀請求入手,我們分三層:
請求流程:
先查本地 → 不命中查Redis → 仍不命中查MySQL並回填。
這樣能減少Redis壓力,同時也為“熱點更新”打基礎。
第2層:熱度統計與異步上報
想知道哪些數據是熱點,不能靠猜,要靠訪問統計。
我們在應用層引入一個“熱度計數器”,每次用户訪問商品詳情時,就上報一次訪問記錄。這裏有兩種實現方式:
1、方案A:本地統計 + 定時上報
- 每台服務實例維護一個 ConcurrentHashMap<id, count>;
- 每隔1分鐘,把統計結果異步彙總上報到MQ或Kafka;
- 消費端定時計算最近5分鐘的訪問量TopN。
2、方案B:滑動窗口 + Redis計數器
- 在Redis中使用 INCR 記錄訪問次數;
- 設置過期時間(比如10分鐘),形成滑動時間窗口;
- 定時計算最近窗口內訪問量TopN。
最後得到的TopN列表,就是當前“熱點數據候選集”。
第3層:Redis熱點數據維護策略
有了TopN數據,就可以動態維護Redis了。
思路是:
熱點上升 → 自動寫入Redis;
熱點下降 → 自動淘汰。
可以用一個簡單的後台任務來實現:
這樣,Redis就能“自動呼吸”,始終保持最有價值的數據。
加速策略:讓Redis命中率更高
到這裏,我們已經有了冷熱分層 + 熱度更新機制。但想讓系統“更絲滑”,還有一些優化小技巧:
1、熱點預測預熱
在大型活動(如雙十一)前,可以根據歷史訪問日誌提前預測哪些商品會熱,然後批量加載入Redis。
這樣一上線就能防止“冷啓動”導致的擊穿。
2、熱點降級機制
當某一類數據突然暴漲,比如明星商品訪問量暴增時,可以啓用本地緩存或返回靜態化數據頁面,防止Redis被打爆。
3、異步更新 + 雙寫一致性
寫操作時不要直接同步更新Redis,可以採用延遲雙刪策略:
- 刪除緩存;
- 更新數據庫;
- 延遲1秒再刪一次緩存,防止併發髒數據。
4、Redis Key 設計與分片
為了防止單節點熱點,可以給Key加前綴哈希分片,比如:
product:{hash(id)%10}:{id}
保證訪問更均衡。
5、Bloom Filter 防止穿透
對於不存在的數據,用布隆過濾器提前攔截,減少數據庫壓力。
關鍵指標:讓熱點機制“看得見”
很多人做完緩存策略就結束了,但真正的高手,會監控數據熱度變化。
你可以用Prometheus + Grafana監控:
- Redis命中率;
- 熱點數據更新頻率;
- MySQL QPS變化;
- 熱度榜TopN曲線。
一旦發現熱點變動趨勢異常,就能提前擴容或預熱。
面試官的追問:那如果“熱點突發”怎麼辦?
面試官繼續追我問:
“如果某個新商品突然爆紅,系統來不及同步進Redis怎麼辦?”
我答:
“可以結合消息隊列 + 異步監聽機制,讓訪問日誌實時觸發熱點檢測。”
舉個例子:
- 用户訪問詳情 → 上報消息隊列;
- 消費端監聽訪問流量;
- 當某個商品的訪問量在1分鐘內暴漲超過閾值(比如1000次);
- 立即觸發預加載入Redis。
這樣熱點突發也能“秒級響應”。
延伸:還能用哪些“黑科技”?
一些大廠更進一步,甚至會用到:
- LFU (Least Frequently Used) 策略替代LRU;
- Redis + Caffeine 雙緩存協同;
- 基於滑動時間窗口的熱度模型;
- 流式計算(Flink)實時統計訪問量;
- AI 熱點預測(例如基於歷史訪問序列訓練模型)。
這些都能讓熱點數據維護更智能。
總結覆盤:這道題到底考什麼?
其實,這道題考的並不是“你背了多少Redis命令”,而是考察你能不能從業務邏輯、系統設計、數據波動三個維度綜合思考。
我後來總結了一句口訣:
“冷熱分層是骨架,熱度統計是靈魂,動態更新是血液。”
能把這三點講清楚,你不僅能拿下面試,還能寫出真正可落地的方案。
寫在最後
那次面試我順利過了,面試官笑着説:
“你這回答不是背書,是講了個能跑起來的系統。”
我回到家後,心裏還挺有成就感。其實每次面試題背後,都藏着真實的工程智慧。它逼你去思考系統的本質,而不是死記硬背。如果你正準備面Java社招面試,記住這點:
技術不是堆疊,而是思考。
最後送你一句話:
“熱數據永遠有限,但聰明的人能讓有限的資源發揮無限的價值。”
要點覆盤(方便收藏)
END
我是小米,一個喜歡分享技術的31歲程序員。如果你喜歡我的文章,歡迎關注我的微信公眾號“軟件求生”,獲取更多技術乾貨!