
Redis 面試是 Java 崗位繞不過去的一道坎。我做了這么多年后端技術(shù)面試官幾乎每場面試都會問 Redis為什么因為 Redis 是 Java 后端技術(shù)棧里最普及的緩存組件從數(shù)據(jù)緩存、分布式鎖、消息隊列到排行榜幾乎每個互聯(lián)網(wǎng)項目都在用它。面試官只需要圍繞 Redis 的數(shù)據(jù)類型、緩存治理、分布式鎖、持久化和高可用這幾個點就能快速判斷一個候選人是“背過八股文”還是“真在實際項目里解決過問題”。這篇文章我整理了 30 道高頻面試題每一道都給出深度解析和 Java 實戰(zhàn)側(cè)的參考答案。題目分布覆蓋了數(shù)據(jù)類型與底層原理、緩存穿透/擊穿/雪崩、緩存一致性、分布式鎖、持久化與高可用、以及面試官愛挖坑的陷阱題。無論你是準備校招、社招還是想系統(tǒng)地自查一遍 Redis 知識體系這套題都值得你花一個下午徹底過一遍。1. 高頻考點全景面試官到底在考什么1.1 為什么 Redis 是 Java 面試的“必考點”先看一組常見現(xiàn)象候選人簡歷里幾乎都寫著“熟練使用 Redis”但問到“你們的緩存和數(shù)據(jù)庫怎么保證一致性”就冷場問到“用過 Redisson 的看門狗嗎”就只會答“不知道”。這說明大部分人對 Redis 的認知停留在“會用 get/set”而面試官考的是背后三件事數(shù)據(jù)結(jié)構(gòu)的底層原理、緩存的工程治理、以及分布式場景下的方案取舍。從崗位匹配度的角度Java 開發(fā)日常打交道最多的就是 Spring Boot 整合 Redis、緩存與數(shù)據(jù)庫的一致性處理、分布式鎖在訂單/秒殺場景的應用。所以面試官層層深入地問其實是在模擬真實項目的技術(shù)決策過程。你要做的不是背標準答案而是理解每個方案為什么這么設(shè)計。1.2 30 道題的三層分布從背題到說出門道我這 30 道題不是隨便湊的按難度和考察點分為三層層級考察范圍對應章節(jié)目標基礎(chǔ)層數(shù)據(jù)類型、SDS、過期策略、淘汰策略第 2 章確認你真的會用 Redis進階層緩存三大問題、緩存一致性、序列化第 3 章確認你處理過真實緩存問題高級層分布式鎖、持久化、主從/哨兵/集群、故障排查第 4~6 章確認你有架構(gòu)思維和排障能力絕大多數(shù)候選人能過第一層第二層開始出現(xiàn)分化第三層基本是“區(qū)分度題”——能答好的人往往真在線上環(huán)境踩過坑。下面我就按這個分層把題一道道拆開講。2. 數(shù)據(jù)類型與底層原理開局必拿的送分題2.1 五大基本類型的面試深挖【第 1 題】Redis 為什么這么快這道題雖然是“速答題”但面試官想聽的不是“因為內(nèi)存單線程”這六個字。完整的答法要拆成四點純內(nèi)存訪問、單線程避免了上下文切換和鎖競爭、IO 多路復用機制、高效的數(shù)據(jù)結(jié)構(gòu)。如果面試官追問 IO 多路復用請回答 epoll 的事件驅(qū)動模型核心是“一個線程可以同時監(jiān)聽多個 socket事件就緒時才處理”?!镜?2 題】String 類型你們項目中都用來做什么這是高頻中的高頻。String 在 Java 項目中通常做四類事緩存對象JSON 序列化、計數(shù)器INCR 做庫存扣減、點贊數(shù)、分布式 ID、共享 Session。面試官問這道題其實還想順勢考察 SETNX——你已經(jīng)順便踩到了分布式鎖的邊后面第 4 章會展開?!镜?3 題】Hash 和 String 都能存對象實際選哪個我一般建議字段經(jīng)常需要單獨修改時用 Hash比如用戶資料的某個字段更新整體讀寫多、字段固定時用 String。Hash 底層是 listpack新版本替代了 ziplist或 hashtable少量字段時內(nèi)存更省String 適合整體緩存 JSON、不需要從中間字段讀的場景。Java 側(cè) Jedis 的 hgetAll 返回 Map和 MyBatis 查出來的實體類轉(zhuǎn) Map 做合并寫起來非常順手。2.2 底層編碼面試官最愛的原理題【第 4 題】SDS 和 C 字符串有什么區(qū)別為什么 Redis 不用 C 字符串Redis 自己實現(xiàn)了 SDS簡單動態(tài)字符串解決了 C 字符串三個痛點獲取長度從 O(n) 變成 O(1)避免二進制不安全問題C 字符串以 \0 結(jié)尾無法存二進制數(shù)據(jù)SDS 用 len 字段記錄長度減少拼接時的內(nèi)存重新分配開銷。面試時補充一句“SDS 有空間預分配和惰性空間釋放的優(yōu)化”就很加分?!镜?5 題】ZSet 的底層為什么用跳表而不是平衡樹ZSet 底層是跳表 哈希表。哈希表負責 O(1) 查 value 對應的 score跳表負責按 score 排序和范圍查詢。跳表和紅黑樹都能做到 O(logN) 查找但跳表實現(xiàn)更簡單、區(qū)間遍歷方便、不需要頻繁旋轉(zhuǎn)調(diào)整。Redis 作者 Antirez 的考慮是跳表代碼量小、易調(diào)試、性能足夠。這道題能答到“跳表用概率換確定性代碼實現(xiàn)簡單”就夠了。2.3 過期刪除與內(nèi)存淘汰策略【第 6 題】Redis 的過期刪除策略是什么會同時用主動刪除和惰性刪除嗎Redis 用的是惰性刪除 定期刪除的組合。惰性刪除是訪問 key 時發(fā)現(xiàn)過期就刪省 CPU 但可能殘留過期 key 占內(nèi)存定期刪除是后臺每秒輪詢一定數(shù)量的 key刪除其中過期的。只靠這兩種還不夠內(nèi)存仍然可能被寫滿所以需要下面的淘汰策略兜底?!镜?7 題】內(nèi)存淘汰策略有哪些生產(chǎn)環(huán)境怎么選八個策略重點記四個volatile-lru、allkeys-lru、volatile-lfu、allkeys-lfu。一般建議用allkeys-lru或allkeys-lfu。熱點數(shù)據(jù)穩(wěn)定、需抗突發(fā)流量時用 LFU常規(guī)場景用 LRU 即可。Java 側(cè)要注意如果 Redis 做緩存且不設(shè)過期時間volatile-*系列策略等于沒設(shè)防——因為根本沒有 volatile key 可選。這個細節(jié)我見很多人栽過。注意Redis 的 LRU 是一種近似 LRU它并非維護精確的最近訪問鏈表而是從樣本中隨機抽取 key 淘汰目的是降低內(nèi)存開銷。面試中主動點破“近似”兩個字面試官會對你另眼相看。3. 緩存三大問題與緩存一致性Java 側(cè)最能打的實戰(zhàn)題3.1 緩存穿透、擊穿、雪崩三道壓軸題的統(tǒng)一答法這三道題必須放在一起回答因為它們的成因和應對完全不同?!镜?8 題】什么是緩存穿透怎么解決穿透是查了一個不存在的數(shù)據(jù)緩存和數(shù)據(jù)庫都沒有導致請求直接打到數(shù)據(jù)庫。高并發(fā)下就是災難。解決方案有兩類空值緩存不存在的 key 也緩存TTL 設(shè)置短一點比如 60 秒布隆過濾器在緩存前加一層 Bloom Filter不存在就直接返回。Java 實戰(zhàn)里本地用 Guava 的BloomFilter分布式可以用 Redisson 的RBloomFilter初始化時指定預計數(shù)據(jù)量和誤判率。// Guava 布隆過濾器示例 BloomFilterString bloomFilter BloomFilter.create( Funnels.stringFunnel(StandardCharsets.UTF_8), 10000, // 預計插入數(shù)據(jù)量 0.01); // 誤判率 1% bloomFilter.put(userId:10001); boolean mightContain bloomFilter.mightContain(userId:99999); if (!mightContain) { return null; // 直接被攔住 }【第 9 題】緩存擊穿和穿透的區(qū)別擊穿如何解決擊穿是某個熱點 key 在過期瞬間大量請求同時打到數(shù)據(jù)庫。核心解法是互斥鎖只有一個線程能去查庫并重建緩存其他線程等待。Java 代碼用 Redis 的SETNX或者直接上分布式鎖String value redisTemplate.opsForValue().get(key); if (value null) { // 嘗試獲取鎖避免大量請求打到 DB if (tryLock(key :lock, 30, TimeUnit.SECONDS)) { try { value db.query(key); // 真正查庫 redisTemplate.opsForValue().set(key, value, 300, TimeUnit.SECONDS); return value; } finally { releaseLock(key :lock, requestId); } } else { Thread.sleep(100); // 自旋等待 } }另一種方案是邏輯過期緩存里存一個過期時間字段讀取時發(fā)現(xiàn)邏輯過期就異步重建。這種方案對一致性要求低、性能高適合秒殺等場景?!镜?10 題】緩存雪崩怎么處理雪崩是大量 key 同時過期或者 Redis 實例宕機。應對核心就一句讓過期時間更分散讓系統(tǒng)更有韌性。具體四招過期時間加隨機值基本操作Redis 做高可用哨兵/集群多級緩存本地 Caffeine Redis開啟降級和限流Sentinel/Hystrix。Java 側(cè)設(shè)置過期時間時記得// 過期時間 基礎(chǔ)時間 隨機 0~300 秒 int expire 300 RandomUtil.randomInt(0, 300); redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);3.2 緩存與數(shù)據(jù)庫一致性延遲雙刪為什么有兩步【第 11 題】先更新數(shù)據(jù)庫還是先刪緩存為什么常聽到“延遲雙刪”老規(guī)矩先更新數(shù)據(jù)庫再刪除緩存。如果反過來一個線程先刪緩存另一個線程讀到了舊數(shù)據(jù)并回寫緩存此時數(shù)據(jù)庫被更新了——緩存里就留下舊值。而先更新庫再刪緩存即便中間有線程讀到舊值等刪完緩存后舊值也就清掉了下一次讀會回源取新值保證最終一致。那延遲雙刪是干嘛的因為“刪除緩存”這個動作和“數(shù)據(jù)庫更新完成”之間有時間差。假設(shè)刪完緩存后一個已經(jīng)拿到舊值的線程回寫了緩存就需要再刪一次。第一次刪立即執(zhí)行第二次刪延遲 500ms 左右確保把可能回寫的舊值清掉。當然比較嚴謹?shù)淖龇▽懫饋硎沁@樣的// 1. 更新數(shù)據(jù)庫 userService.updateUser(user); // 2. 刪除緩存第一次 redisTemplate.delete(user: user.getId()); // 3. 延遲 500ms 再刪一次第二次 Thread.sleep(500); redisTemplate.delete(user: user.getId());【第 12 題】延遲雙刪不可靠怎么辦有更好的方案嗎能問出“不可靠”的候選人已經(jīng)贏了大多數(shù)人。延遲雙刪本質(zhì)是“概率最終一致”如果中間又發(fā)生寫請求還是可能臟讀。工程上更可靠的方案是異步訂閱數(shù)據(jù)庫 binlogCanal 監(jiān)聽在刪除緩存時通過 MQ 廣播保證最終刪除或者用事務(wù)消息先發(fā) MQ 再提交業(yè)務(wù)消息消費時刪緩存。前端更簡單粗暴的做法讀請求設(shè)置很短的緩存 TTL比如 5 分鐘讓不一致的窗口期更短。3.3 Spring Boot 中 Redis 緩存的配置與序列化【第 13 題】RedisTemplate 默認序列化有什么問題為什么 key 有時會出現(xiàn)亂碼這是 Java 面試專屬題不熟的人特別多。RedisTemplate默認使用JdkSerializationRedisSerializer序列化 key 和 value。結(jié)果是 key 在 Redis 客戶端里長這樣\xac\xed\x00\x05t\x00\x05user:1。排查問題時看到這種“亂碼”先不要慌是序列化方式的問題不是數(shù)據(jù)壞了。解決辦法就是顯式配置序列化器。生產(chǎn)環(huán)境我建議 key 用StringRedisSerializervalue 用GenericJackson2JsonRedisSerializer。后者會額外存入class信息反序列化時能還原成對應的 Java 類型代價是緩存體積稍大。如果不想存class可以自己封裝一個不帶類型信息的序列化器缺點是對復雜泛型類型兼容性差。LocalDateTime是另一個大坑Jackson 默認無法序列化 Java 8 時間類型需要在ObjectMapper里注冊JavaTimeModule。我見過太多同事在啟動后才發(fā)現(xiàn)緩存寫入直接報InvalidDefinitionException。4. 分布式鎖一場面試撐起半場戲的高級題4.1 從 SETNX 到 SET NX PX分布式鎖的演進【第 14 題】用 Redis 實現(xiàn)分布式鎖最基礎(chǔ)的方式是什么基礎(chǔ)答案是SETNX key value只在 key 不存在時才能設(shè)置成功。但這道題的完整答法要講出三個坑并且給出每個坑的解法沒設(shè)過期時間——拿到鎖的線程掛了鎖永久不釋放。解法加鎖時用SET key value NX PX 30000原子設(shè)置過期時間。刪鎖把自己的鎖刪了——線程 A 鎖過期后線程 B 拿到鎖A 業(yè)務(wù)執(zhí)行完把 B 的鎖刪了。解法value 存一個唯一 ID比如 UUID刪除前先比較一致才刪。刪除不是原子操作——先 GET 再 DEL 之間鎖可能過期。解法用 Lua 腳本保證“判斷刪除”兩步原子執(zhí)行。// 加鎖原子操作 String requestId UUID.randomUUID().toString(); Boolean success redisTemplate.opsForValue() .setIfAbsent(key, requestId, 30, TimeUnit.SECONDS); // 釋放鎖Lua 腳本保證原子性 String script if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end; DefaultRedisScriptLong redisScript new DefaultRedisScript(script, Long.class); redisTemplate.execute(redisScript, Collections.singletonList(key), requestId);【第 15 題】SETNX 實現(xiàn)的鎖有什么缺陷Redisson 解決了什么SETNX 手動過期時間有三層問題過期時間設(shè)多少拿不準業(yè)務(wù)沒執(zhí)行完鎖就過期了不可重入同一線程重復獲取會死鎖非阻塞獲取不到鎖只能自己循環(huán)。Redisson 通過一個RLock接口把這些問題都解決了它的核心機制是看門狗Watch Dog。4.2 Redisson 看門狗與鎖續(xù)期面試加分項【第 16 題】Redisson 的看門狗是怎么工作的Redisson 加鎖默認鎖超時時間是 30 秒。如果拿到鎖的線程還在執(zhí)行Redisson 的后臺定時任務(wù)會每隔 10 秒給鎖續(xù)期 30 秒鎖剩余時間 / 3。這意味著業(yè)務(wù)只要沒結(jié)束鎖就不會被提前回收。面試官問“看門狗”時記得說全三點啟動時機是加鎖成功時默認參數(shù) leaseTime30s、續(xù)期間隔10s用getLock后不傳leaseTime才會啟用看門狗自定義了過期時間反而不會自動續(xù)期。RLock lock redissonClient.getLock(order: orderId); if (lock.tryLock(3, TimeUnit.SECONDS)) { try { // 業(yè)務(wù)處理 } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }【第 17 題】Redis 分布式鎖真的絕對安全嗎RedLock 是什么這個問題是在考察候選人的思辨能力。Redis 主節(jié)點在鎖寫入后發(fā)生故障切換鎖數(shù)據(jù)還沒同步到從節(jié)點新主節(jié)點沒有鎖信息其他線程就能重新加鎖導致并發(fā)問題。RedLock紅鎖的解法是向多個獨立 Redis 節(jié)點依次加鎖超過半數(shù)成功才算加鎖成功。但分布式系統(tǒng)專家 Martin Kleppmann 專門寫文章論證過 RedLock 在極端場景GC pause、時鐘跳躍下也不完全可靠。我的建議面試時表態(tài)“生產(chǎn)環(huán)境單機 Redisson 看門狗足夠 99.9% 場景如果要求強一致直接用 ZooKeeper 或 etcd不要用 Redis”——這個回答在面試官那里非常加分。4.3 手寫鎖的經(jīng)典代碼與常見 Bug【第 18 題】Redis 分布式鎖的可重入是怎么實現(xiàn)的Redisson 可重入鎖用 Hash 數(shù)據(jù)結(jié)構(gòu)實現(xiàn)key 是鎖名field 是客戶端 UUID線程 IDvalue 是重入計數(shù)。加鎖時HSET判斷是否存在存在則HINCRBY把計數(shù)加一釋放鎖時遞減計數(shù)歸零才真正刪除 key。手寫可重入鎖最容易忽略的就是“同線程重入”和“不同線程的歸屬校驗”這兩個條件?!镜?19 題】 getLock().unlock() 和 lock() 的典型錯誤用法最常見的錯誤是 unlock 前不判斷當前線程是否持有鎖——鎖已經(jīng)因為超時釋放、其他線程持有時unlock()會把別人的鎖刪掉。正確姿勢就是前文代碼里的isHeldByCurrentThread()判斷。第二個錯誤是 tryLock 失敗后不處理直接往下走業(yè)務(wù)代碼導致本來該串行的邏輯并發(fā)執(zhí)行。第三個錯誤是拿到鎖后業(yè)務(wù)里發(fā)生異常忘記 releaseLock鎖活活等到過期才釋放。5. 持久化與高可用架構(gòu)題的必答清單5.1 RDB 與 AOF怎么選、怎么配合【第 20 題】RDB 和 AOF 的區(qū)別項目里怎么選RDB 是內(nèi)存快照fork 子進程寫入臨時文件文件小、恢復快但可能丟失最后一次持久化數(shù)據(jù)。AOF 是命令追加日志默認 everysec 刷盤最多丟 1 秒數(shù)據(jù)文件大、恢復慢極端情況下可能出現(xiàn)命令重放帶來的不確定性。現(xiàn)在 Redis 4.0 有混合持久化RDB 存全量快照AOF 存增量命令兼顧恢復速度和數(shù)據(jù)完整性。面試時結(jié)合業(yè)務(wù)說是最佳策略——可以容忍 1 分鐘丟失用 RDB不能丟數(shù)據(jù)用混合持久化?!镜?21 題】BGSAVE 的 fork 會不會阻塞主進程會不是完全不阻塞。fork 瞬間需要復制父進程頁表內(nèi)存越大耗時越長之后采用 copy-on-write寫時復制子進程與主進程共享內(nèi)存頁主進程發(fā)生寫操作才復制對應內(nèi)存頁。只要 QPS 高fork 帶來的額外內(nèi)存開銷和短暫的 Redis 抖動是真實存在的。面試時提到“大實例 fork 耗時可能達到秒級建議單實例內(nèi)存控制在 10G 以內(nèi)”這句話就成功區(qū)分了你和背題黨。5.2 主從、哨兵、Cluster 的面試要點【第 22 題】主從復制的原理是什么主從復制分全量同步和增量同步。初始化時從節(jié)點發(fā)送PSYNC主節(jié)點執(zhí)行 BGSAVE 生成 RDB 快照發(fā)給從節(jié)點同時用 repl_backlog 緩沖區(qū)記錄后續(xù)命令之后主節(jié)點把增量命令實時推送給從節(jié)點。重點說三個關(guān)鍵詞repl_backlog環(huán)形緩沖區(qū)決定增量同步的容錯范圍、主從延遲寫主庫后從庫可能落后幾毫秒到幾秒、從節(jié)點只讀避免寫入沖突?!镜?23 題】哨兵模式的作用為什么至少要 3 個節(jié)點哨兵負責監(jiān)控主節(jié)點狀態(tài)、自動故障轉(zhuǎn)移。判定流程哨兵發(fā)現(xiàn)主節(jié)點主觀下線SDOWN后向其他哨兵確認超過 quorum 個哨兵確認后判定客觀下線ODOWN然后執(zhí)行選舉選一個從節(jié)點升級為主節(jié)點。為什么至少 3 個節(jié)點因為故障轉(zhuǎn)移需要哨兵集群自己達成多數(shù)派決策比如 quorum2 時至少需要 3 個哨兵否則腦裂情況下兩個哨兵無法形成多數(shù)派系統(tǒng)無法自動恢復?!镜?24 題】Cluster 集群為什么要用 16384 個槽Java 側(cè)要注意什么Redis Cluster 用 CRC16 算法計算 key再對 16384 取模定位到槽位槽位映射到具體節(jié)點。16384 這個數(shù)字是設(shè)計權(quán)衡槽越少節(jié)點間交換槽位信息的網(wǎng)絡(luò)開銷越低槽越多數(shù)據(jù)分布越均勻。Java 側(cè)要注意Jedis 連接 Cluster 時要配置集群節(jié)點列表Spring Boot 用spring.redis.cluster.nodes另外 Cluster 模式不支持 multi-key 跨節(jié)點操作比如 mget 涉及不同槽位會報錯需要使用 hash tag 如{user1}:name{user1}:age讓 key 落在同一槽。5.3 緩存雪崩后的 Java 側(cè)兜底方案【第 25 題】如果 Redis 不可用了你們的接口會直接雪崩嗎有沒有兜底這是一道系統(tǒng)性設(shè)計題不能只答“我們有監(jiān)控告警”。成熟的方案是二級緩存Caffeine 本地緩存作為一級Redis 作為二級DB 作為最后屏障。Redis 掛了Caffeine 里的數(shù)據(jù)還能撐住相當一部分流量。配合 Sentinel 或 Resilince4j 的熔斷降級對 DB 的訪問控制在安全水位。CacheString, Object localCache Caffeine.newBuilder() .maximumSize(5000) .expireAfterWrite(60, TimeUnit.SECONDS) .build(); // 查詢順序: 本地緩存 - Redis - DB Object value localCache.get(key, k - { Object v redisTemplate.opsForValue().get(k); if (v null) { v db.query(k); // 熔斷器保護 redisTemplate.opsForValue().set(k, v, 300, TimeUnit.SECONDS); } return v; });6. 高頻陷阱題與避坑實錄來自真實面試現(xiàn)場6.1 面試官在紙上挖好的 5 個坑【第 26 題】Redis 6.0 引入多線程是不是“單線程”神話破了Redis 命令執(zhí)行仍然是單線程多線程只用于網(wǎng)絡(luò) IO 讀寫和協(xié)議解析。引入多線程是為了緩解高并發(fā)場景下網(wǎng)絡(luò) IO 的瓶頸命令執(zhí)行核心依然是單線程串行。這個區(qū)分就是這道題的考點答“不是執(zhí)行還是單線程”就是標準答案?!镜?27 題】大 key 刪除會怎么樣生產(chǎn)上遇到過嗎大 key 是字符串 value 超過幾 MB、集合元素達到幾百萬個這樣的 key。直接DEL一個包含幾百萬成員的 SetRedis 單線程在刪除期間會卡住其他命令排隊等待造成整個實例的延遲甚至超時。生產(chǎn)上的處理方式字符串大 value 用UNLINK異步刪除集合類用SSCAN、HSCAN、ZSCAN漸進式分批刪除最根本的辦法是拆分 key比如把一個大集合拆成 N 個小的 hash key 或 set key。檢測腳本配合redis-cli --bigkeys可以快速發(fā)現(xiàn)大 key。【第 28 題】熱 key 導致單節(jié)點壓力過大怎么解決熱 key 是某個 key 的流量占到了 Redis 實例總流量的很大比例比如微博熱搜、爆款商品的庫存。應對思路本地緩存 Caffeine 抗熱點把熱 key 復制成多份加后綴如hotkey:1、hotkey:2分散到不同節(jié)點限流降級避免打掛 DB。Java 側(cè)識別熱 key 可以在讀取時給 key 加本地計數(shù)或用 Redis 的hotkeys命令、監(jiān)聽命令延遲等?!镜?29 題】緩存預熱怎么做緩存預熱的本質(zhì)是提前把熱點數(shù)據(jù)加載到緩存避免上線后大量 miss 打掛 DB。常見做法項目啟動時寫一個ApplicationRunner把歷史熱點數(shù)據(jù)按熱度排序后分批寫入 Redis注意控制寫入速度避免啟動瞬間 QPS 打滿。更工程化的方案離線分析日志統(tǒng)計熱點數(shù)據(jù)推送到 MQ消費者預熱緩存?!镜?30 題】Java 側(cè) Redis 連接池怎么配連接池滿怎么辦Jedis 和 Lettuce 都有連接池配置核心參數(shù)是maxTotal最大連接數(shù)、maxIdle最大空閑數(shù)、maxWaitMillis獲取連接最大等待時間。常規(guī)建議單個 Redis 實例內(nèi)網(wǎng)環(huán)境下maxTotal50~200 足夠。連接池滿說明兩條路調(diào)大連接數(shù)或檢查是否有連接泄漏沒歸還連接同時排查慢查詢——某個命令執(zhí)行太慢會占住連接不釋放。spring: redis: host: 127.0.0.1 port: 6379 lettuce: pool: max-active: 100 # 最大連接數(shù) max-idle: 50 # 最大空閑連接 min-idle: 10 # 最小空閑連接 max-wait: 3000ms # 獲取連接超時時間排查連接池滿問題時我建議先看兩個指標Redis 的connected_clients和命令的slowlog。曾經(jīng)遇到一個線上事故某個接口在循環(huán)里頻繁 new Jedis 對象不關(guān)閉直接把 Redis 連接數(shù)打滿排查了很久才發(fā)現(xiàn)是同事寫的工具類沒有用連接池。6.2 實戰(zhàn)中的 Redis 故障排查實錄這里分享一個真實案例。某次大促前壓測發(fā)現(xiàn) Redis 訪問延遲從 1ms 飆到 200ms。排查路徑如下先看INFO stats發(fā)現(xiàn)used_memory漲了 20%進一步排查發(fā)現(xiàn)大量帶序號的臨時促銷 key 都設(shè)置了不合理的 TTL。然后用redis-cli --latency確認不是網(wǎng)絡(luò)問題用slowlog get看到一個HGETALL命令耗時 800ms——對應一個百萬字段的 Hash 大 key。當場解決把這個大 key 拆分成按日期分片的小 key壓測延遲回到 2ms 以內(nèi)。這個案例說明Redis 的問題大多是數(shù)據(jù)模型設(shè)計問題不是性能問題。面試時能講出類似的排障鏈路比背十道八股文都管用。最后再分享一個我在面試里反復給人講的心得30 道題不是背完就算過關(guān)面試官只需要隨機挑兩三道深挖就能判斷你是真懂還是假懂。真正穩(wěn)妥的做法是拿著這套題自己動手把緩存治理代碼、分布式鎖代碼、序列化配置在 Spring Boot 項目里跑一遍把原理跟代碼對照著看。紙上得來終覺淺Redis 尤其如此。