騰訊二面被刷!被問"你們項目為啥用Redis",我張口就說"提升性能降低數(shù)據(jù)庫壓力",面試官:就這?
一、簡歷寫了Redis,面試卻答不上來?
上周幫學弟復盤騰訊二面,全程替他尷尬。
簡歷上寫著:"熟練使用Redis緩存,優(yōu)化系統(tǒng)性能,解決高并發(fā)問題。"
面試官看了眼簡歷:"看你簡歷寫了Redis,說說你們項目為什么要用Redis?"
學弟張口就來:"Redis是基于內(nèi)存的NoSQL數(shù)據(jù)庫,讀寫速度快,可以提升性能,降低數(shù)據(jù)庫壓力。"
面試官:"嗯,然后呢?"
學弟:"然后就是緩存熱點數(shù)據(jù),減少數(shù)據(jù)庫查詢。"
面試官:"就這?你說的這些不都是Redis的定義嗎?我問的是你們項目為什么用,不是問Redis是什么。"
學弟支支吾吾:"就是...數(shù)據(jù)庫慢,所以用Redis加速..."
面試官:"數(shù)據(jù)庫慢?慢到什么程度?QPS多少?響應時間多少?用了Redis之后呢?具體數(shù)據(jù)呢?"
學弟懵了。
面試官繼續(xù)追問:"你說緩存熱點數(shù)據(jù),什么數(shù)據(jù)算熱點?為什么不直接擴容數(shù)據(jù)庫?Redis掛了怎么辦?緩存和數(shù)據(jù)庫數(shù)據(jù)不一致怎么解決?"
學弟徹底卡殼了。
二面,涼了。
二、問題出在哪?背概念≠做過項目
很多人面試一說Redis,就是"內(nèi)存存儲、高性能、支持多種數(shù)據(jù)結構",這不是廢話嗎?
面試官問你為什么用Redis,考的不是你背概念的能力,考的是你有沒有真正在項目里解決過問題。
大廠面試官想聽的是:
- 你的系統(tǒng)遇到了什么具體問題(痛點)
- 為什么選擇用Redis解決(方案選型)
- 怎么用的,用了之后效果如何(具體數(shù)據(jù)對比)
- 遇到過什么坑,怎么解決的(深度思考)
你張口就說"提升性能",那我問你:
- 性能提升了多少?從多少Q(mào)PS提升到多少Q(mào)PS?
- 響應時間優(yōu)化了多少?從多少毫秒降到多少毫秒?
- 為什么不用Memcached?為什么不直接加數(shù)據(jù)庫索引?
- 你緩存的過期時間怎么設置的?為什么?
答不上來,就是沒做過項目。
三、真實項目場景:這才是Redis的正確打開方式
場景1:商品詳情頁的性能優(yōu)化
痛點:數(shù)據(jù)庫扛不住了
去年做電商項目,商品詳情頁是整個系統(tǒng)訪問量最大的接口,每天幾千萬次請求。
最開始沒用緩存,所有請求都打到MySQL。商品詳情的SQL雖然加了索引,但關聯(lián)查詢還是要掃好幾張表:商品基本信息、庫存、價格、評價統(tǒng)計、店鋪信息。
數(shù)據(jù)庫的問題來了:
- 查詢一次商品詳情,數(shù)據(jù)庫耗時平均150-200ms
- 大促期間流量暴增,MySQL連接池直接打滿
- 接口響應時間飆到500ms以上,大量請求超時
- 數(shù)據(jù)庫CPU直接打到85%,隨時可能掛
老板直接找過來:"詳情頁這么慢,用戶體驗太差了,趕緊優(yōu)化!"
方案:Redis緩存熱點商品
分析了下流量分布,發(fā)現(xiàn)典型的二八定律:20%的熱門商品占了80%的訪問量。
像iPhone、爆款零食這些商品,每秒被查詢幾百次,但數(shù)據(jù)其實不怎么變。每次都查數(shù)據(jù)庫完全是浪費。
用Redis緩存熱點商品數(shù)據(jù):
- 商品詳情訪問流程
- 先查Redis,命中直接返回
- Redis沒有,查MySQL,然后寫入Redis
- 設置過期時間30分鐘,熱點數(shù)據(jù)自動續(xù)期
- 緩存結構選擇
- 用String類型存商品詳情JSON
- key設計:product:detail:{productId}
- value:完整的商品詳情JSON字符串
- 熱點數(shù)據(jù)預熱
- 每天凌晨3點,把銷量Top 10000的商品預熱到Redis
- 大促前1小時,把活動商品全部預熱
效果:性能提升10倍
圖片
上線Redis緩存后,效果立竿見影:
指標 | 優(yōu)化前 | 優(yōu)化后 | 提升 |
平均響應時間 | 180ms | 15ms | 提升12倍 |
緩存命中率 | 0% | 92% | - |
MySQL QPS | 2000 | 160 | 降低92.5% |
數(shù)據(jù)庫CPU | 85% | 25% | 降低71% |
接口可承載QPS | 500 | 8000+ | 提升16倍 |
大促當天,詳情頁QPS破萬,系統(tǒng)穩(wěn)如老狗,MySQL壓力小到可以忽略。
這才是面試官想聽的答案。
場景2:分布式鎖解決秒殺超賣
痛點:單機鎖在分布式環(huán)境下失效
系統(tǒng)部署了4臺服務器做負載均衡,秒殺活動第一次上線就翻車了。
商品庫存只有100件,結果賣出去了130件,直接超賣了30件。用戶投訴,運營部直接炸了。
問題出在哪?
秒殺扣庫存的邏輯:
- 查詢庫存是否充足
- 如果充足,庫存-1,生成訂單
圖片
在單機環(huán)境下,用synchronized加鎖沒問題。但4臺服務器各自加鎖,鎖只能鎖住單機的線程,分布式環(huán)境下synchronized完全失效。
服務器A:查到庫存1 → 準備扣庫存
服務器B:查到庫存1 → 準備扣庫存 // 同時查到了庫存1
服務器A:扣庫存成功,庫存變0
服務器B:扣庫存成功,庫存變-1 // 超賣了!方案:Redis實現(xiàn)分布式鎖
圖片
用Redis的SETNX命令實現(xiàn)分布式鎖:
- 搶鎖:SET lock:seckill:{productId} {requestId} NX EX 5
- NX:key不存在才能設置成功
- EX 5:設置過期時間5秒,防止死鎖
- requestId:唯一標識,防止誤刪別人的鎖
- 執(zhí)行業(yè)務:扣庫存、生成訂單
- 釋放鎖:用Lua腳本保證原子性
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end效果:徹底解決超賣
上線分布式鎖后:
- 秒殺10000件商品,賣出10000件,庫存精準為0
- 4臺服務器同時搶鎖,同一時刻只有1臺能扣庫存
- 沒搶到鎖的請求快速失敗,返回"商品已搶完"
- 接口響應時間控制在50ms以內(nèi)
后續(xù)10次大促活動,0次超賣事故。
場景3:Session共享解決分布式登錄
痛點:用戶登錄狀態(tài)丟失
系統(tǒng)剛上線的時候,用戶經(jīng)常投訴"登錄了還是跳轉(zhuǎn)到登錄頁"。
原因是Session默認存在應用服務器內(nèi)存里,用戶第一次請求打到服務器A登錄成功,第二次請求負載均衡打到服務器B,服務器B沒有Session,判定用戶未登錄,又跳轉(zhuǎn)到登錄頁。
用戶體驗極差。
方案:Redis集中存儲Session
把所有服務器的Session統(tǒng)一存到Redis:
- 用戶登錄成功
- 生成唯一token:UUID.randomUUID()
- Redis存儲:SET session:{token} {userInfo} EX 7200(2小時過期)
- 返回token給客戶端,存到Cookie
- 后續(xù)請求驗證
- 從Cookie取出token
- Redis查詢:GET session:{token}
- 查到就是登錄狀態(tài),查不到就是未登錄
- 續(xù)期機制
- 每次請求驗證通過后,重置過期時間
- 保持2小時無操作才過期
效果:用戶體驗絲滑
指標 | 優(yōu)化前 | 優(yōu)化后 |
登錄態(tài)丟失投訴 | 每天50+ | 0 |
Session查詢耗時 | - | <5ms |
支持服務器數(shù)量 | 受限 | 無限水平擴展 |
無論負載均衡怎么切換服務器,用戶登錄態(tài)永遠有效。服務器隨便擴容縮容,不影響用戶體驗。
四、面試官的進階追問:你扛得住嗎?
如果你按上面的方式回答,面試官大概率會繼續(xù)追問。這些追問才是真正拉開段位的地方。
追問1:緩存和數(shù)據(jù)庫數(shù)據(jù)不一致怎么辦?
場景:商品價格改了,數(shù)據(jù)庫更新了,但Redis還是舊數(shù)據(jù),用戶看到的價格不對。
回答思路:
我們項目用的是先更新數(shù)據(jù)庫,再刪除緩存的策略:
- 為什么不是更新緩存?
- 更新緩存涉及復雜計算(關聯(lián)查詢、統(tǒng)計),開銷大
- 有些數(shù)據(jù)更新頻繁但訪問少,更新緩存浪費
- 刪除緩存簡單高效,下次查詢自動加載最新數(shù)據(jù)
- 為什么是先更新數(shù)據(jù)庫?
- 如果先刪緩存再更新數(shù)據(jù)庫,并發(fā)請求會把舊數(shù)據(jù)重新寫入緩存
- 先更新數(shù)據(jù)庫再刪緩存,雖然有短暫不一致窗口,但概率極小
- 雙刪策略
- 更新數(shù)據(jù)庫后立即刪除緩存
- 延遲500ms再刪除一次
- 確保并發(fā)情況下的數(shù)據(jù)一致性
- 對一致性要求極高的數(shù)據(jù)
- 比如賬戶余額,不用緩存,直接查數(shù)據(jù)庫
- 或者用分布式事務(Seata)保證強一致性
追問2:緩存穿透、擊穿、雪崩怎么解決?
圖片
緩存穿透:查詢不存在的數(shù)據(jù)
問題:惡意用戶瘋狂查詢不存在的商品ID,緩存沒有,數(shù)據(jù)庫也沒有,每次都打到數(shù)據(jù)庫。
解決方案:
- 布隆過濾器把所有商品ID加載到布隆過濾器,查詢前先過濾
- 緩存空值數(shù)據(jù)庫查不到,在Redis存一個空值,過期時間設短一點(5分鐘)
我們項目用的是布隆過濾器,攔截了99%的無效請求。
緩存擊穿:熱點數(shù)據(jù)過期
問題:某個熱點商品緩存過期,瞬間大量請求打到數(shù)據(jù)庫。
解決方案:
- 互斥鎖第一個請求加載數(shù)據(jù)時加鎖,其他請求等待
- 熱點數(shù)據(jù)永不過期在緩存層面設置邏輯過期時間,后臺異步更新
我們對核心商品(iPhone等)用的是永不過期策略,配合異步刷新。
緩存雪崩:大量緩存同時過期
問題:凌晨3點預熱了1萬個商品,30分鐘后同時過期,瞬間數(shù)據(jù)庫扛不住。
解決方案:
- 過期時間加隨機值30分鐘±5分鐘隨機,避免同時過期
- 多級緩存Redis掛了還有本地緩存(Guava Cache)兜底
- 限流降級數(shù)據(jù)庫扛不住時,直接返回降級數(shù)據(jù)
我們項目用了過期時間隨機化+本地緩存,大促期間Redis重啟,系統(tǒng)毫無波動。
追問3:Redis單線程為什么這么快?
回答要點:
- 純內(nèi)存操作內(nèi)存讀寫速度遠超磁盤,ns級別
- 單線程避免上下文切換沒有鎖競爭,沒有線程切換開銷
- IO多路復用epoll模型,一個線程處理上萬連接
- 高效的數(shù)據(jù)結構SDS、跳表、壓縮列表,針對性優(yōu)化
Redis的瓶頸不在CPU,在網(wǎng)絡IO和內(nèi)存,所以單線程反而更快。
五、總結:這才是大廠想聽的答案
下次面試官問你"為什么用Redis",別再說"提升性能"這種正確的廢話了。
標準答題模板:
1. 說場景
"我們電商系統(tǒng)的商品詳情頁,日訪問量5000萬,是整個系統(tǒng)流量最大的接口。"
2. 說痛點
"最開始所有請求都打MySQL,查詢耗時150-200ms,大促期間數(shù)據(jù)庫CPU打到85%,接口大量超時。"
3. 說方案
"分析發(fā)現(xiàn)20%的熱門商品占80%流量,我們用Redis緩存熱點數(shù)據(jù),key設計為product:detail:{id},過期時間30分鐘,并做了熱點數(shù)據(jù)預熱。"
4. 說數(shù)據(jù)
"上線后,緩存命中率92%,響應時間從180ms降到15ms,MySQL QPS從2000降到160,數(shù)據(jù)庫CPU從85%降到25%,接口承載能力從500 QPS提升到8000+ QPS。"
5. 說深度
"我們還解決了緩存一致性問題,用的是先更新數(shù)據(jù)庫再刪緩存+延遲雙刪策略。針對緩存穿透用了布隆過濾器,緩存擊穿對熱點數(shù)據(jù)做了永不過期+異步刷新,緩存雪崩用了過期時間隨機化+本地緩存兜底。"
這才是大廠面試官想聽的答案。
有場景、有數(shù)據(jù)、有思考、有深度。
別再背"Redis是內(nèi)存數(shù)據(jù)庫、支持五大數(shù)據(jù)結構"這種八股文了,面試官聽吐了。
下次面試,你就這么答,保證面試官對你刮目相看!





























