架構(gòu)面試知識點深度剖析)
金三銀四的跳槽季又快到了后臺也陸續(xù)有讀者來問現(xiàn)在面Java后端Spring Boot和微服務(wù)到底還問不問、怎么問。我的答案很直接——問而且問得越來越細、越來越往原理上鉆。前陣子一位朋友面完某中型互聯(lián)網(wǎng)公司的Java后端崗回來跟我復盤了一整輪一面問自動配置的底層加載機制二面直接讓他從單體拆微服務(wù)的角度講自己的設(shè)計方案三面則在分布式事務(wù)和鏈路追蹤上磨了大半個小時。我自己也偶爾參與技術(shù)面試坐在面試官的位置上看很多候選人的問題不是“不懂”而是“懂得太淺”能說出Spring Boot“自動配置”四個字卻說不清楚條件裝配是怎么工作的能背出Eureka、Nacos、ZooKeeper的名字卻講不明白AP和CP的區(qū)別到底意味著什么。這篇文章就站在兩個視角的交匯處把從Spring Boot到微服務(wù)架構(gòu)這條線上高頻出現(xiàn)的面試問題、背后原理、以及實戰(zhàn)中真正有價值的回答思路系統(tǒng)性地梳理一遍。適合正在準備Java后端面試的讀者也適合想從單體轉(zhuǎn)向微服務(wù)方向、但還沒形成完整知識框架的朋友。1. 自動配置的運行機制拉差距的地方就在這里面試菜鳥和資深候選人的差別往往從第一個Spring Boot問題就開始顯現(xiàn)。“說說Spring Boot的自動配置原理”——這道題幾乎每次面試都會出現(xiàn)但九成回答都停留在同一句話“通過spring.factories文件讀取配置類然后按條件生效?!比缓缶蜎]下文了。面試官問這個問題的真正目的是想知道你有沒有真的打開過源碼有沒有理解“按條件生效”這幾個字里包含的整套機制。1.1 SpringBootApplication其實是三個注解的組合很多人天天寫SpringBootApplication但沒想過這個注解其實是個合成注解。它由另外三個注解組合而成SpringBootConfiguration本質(zhì)是Configuration標記這是一個配置類允許注冊額外的Bean。EnableAutoConfiguration整個自動配置的開關(guān)負責導入自動配置的入口。ComponentScan掃描當前包及其子包下帶Component、Service、Repository等注解的類。面試如果要表現(xiàn)深度可以主動補一句真正起作用的是EnableAutoConfiguration它通過Import(AutoConfigurationImportSelector.class)的方式把一批自動配置類批量導入容器。什么叫ImportSelector簡單說就是“由代碼邏輯來挑選需要導入哪些類”而不是在注解里直接寫死。這個設(shè)計讓Spring Boot能夠掃描classpath再結(jié)合已有的依賴和環(huán)境動態(tài)決定加載什么。如果面試官追問“Spring Boot和Spring的區(qū)別”也可以從這層切入Spring Boot沒有改變Spring的核心編程模型DI、AOP、事件機制通通保留它做的是“封裝約定優(yōu)于配置”讓你不用寫一堆模板化配置而是基于classpath依賴和配置項自動推斷。1.2 條件裝配Spring Boot如何判斷“該不該啟動這個配置”自動配置的難點在于“怎么知道當前項目需要哪些配置”。答案是條件裝配Conditional Annotation。Spring Boot的每個自動配置類上都會掛著一組ConditionalOnXxx注解包括但不限于ConditionalOnClass/ConditionalOnMissingClass判斷classpath是否存在某個類。ConditionalOnBean/ConditionalOnMissingBean判斷容器中是否已經(jīng)存在某個Bean。ConditionalOnProperty判斷指定配置項是否為期望值。ConditionalOnWebApplication判斷當前應(yīng)用是否是Web項目。舉個例子RedisAutoConfiguration這個自動配置類上就標注了ConditionalOnClass(RedisOperations.class)。如果項目沒有引入Redis相關(guān)依賴classpath里壓根沒有這個類整段配置直接跳過只有引進了spring-boot-starter-data-redis這個類才可能生效。而.class內(nèi)部的兩個RedisTemplate Bean定義上又標注了ConditionalOnMissingBean意思是如果你自己定義了RedisTemplate默認的不會覆蓋你的自定義Bean?!按嬖诓派А焙汀皼]有才生效”這兩條組合在一起就構(gòu)成了自動配置的“不打臉”邏輯框架給你一套默認值但你隨時可以聲明自定義Bean來覆蓋容器不會因為你沒注意細節(jié)而悄悄替換掉你精心調(diào)過的配置。這里有一個面試加分細節(jié)調(diào)小debugtrue啟動應(yīng)用Spring Boot會打印一份自動配置報告包含“Positive matches”和“Negative matches”前者是生效的自動配置后者是未生效的配置及原因。我第一次排查“為什么配置沒生效”就是靠它定位的——那時候才發(fā)現(xiàn)問題不在配置本身而是classpath缺了一個依賴條件裝配直接判了“不滿足”。1.3 現(xiàn)場手寫一個自定義starter的操作思路面試官如果問到這里還不肯停下一步大概率是“如果讓你自己寫一個starter你怎么設(shè)計”這個問題不是在考你能不能背出API而是在看你對自動配置機制是否真的吃透了。一個規(guī)范的自定義starter應(yīng)該按下面這條鏈路來做第一步創(chuàng)建一個autoconfigure模塊里面放一個帶AutoConfiguration注解的配置類再配合條件注解控制生效時機。AutoConfiguration ConditionalOnClass(MyService.class) EnableConfigurationProperties(MyProperties.class) public class MyServiceAutoConfiguration { Bean ConditionalOnMissingBean public MyService myService(MyProperties properties) { return new MyService(properties.getHost(), properties.getPort()); } }第二步定義配置屬性類通過ConfigurationProperties把application.yml里的前綴配置自動綁定進來。ConfigurationProperties(prefix my.demo) public class MyProperties { private String host localhost; private int port 8080; // getter / setter 省略 }第三步在META-INF/spring.factories里注冊自動配置類Spring Boot 3.x 之后文件路徑變了見下一節(jié)。org.springframework.boot.autoconfigure.EnableAutoConfiguration\ com.example.MyServiceAutoConfiguration第四步創(chuàng)建一個只負責“引入依賴”的starter模塊它的pom里就一件事情——依賴上面那個autoconfigure模塊。這樣用戶引入starter時就直接連帶拿到自動配置邏輯。這個設(shè)計的妙處在于“你根本沒有感覺到配置存在它就生效了”。而能讓用戶覆蓋默認行為的關(guān)鍵就是ConditionalOnMissingBean——這條紀律在寫自己的starter時一點都不能省否則會造成Bean覆蓋沖突和詭異的啟動順序問題。1.4 新舊版本差異Spring Boot 3.x 的加載方式變化還有一個容易被忽略、但一旦說出口就是明顯加分項的細節(jié)Spring Boot 3.0 之后自動配置的注冊文件不再是META-INF/spring.factories而是改成了META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。內(nèi)容也從“鍵值對”簡化成了“一行一個全限定類名”。為什么這么改因為spring.factories可以被很多框架共用每個框架往同一個文件里塞不同key的內(nèi)容解析起來存在識別歧義和性能開銷。獨立出來的.imports文件定位更清晰加載效率也更高。Spring Boot 3.x 同時把基線提到了Java 17并且將javax命名空間遷移到j(luò)akarta。面試時如果主動提到“老項目如果是Boot 2.x遷到3.x需要先改依賴坐標、再改命名空間、最后排查自動配置變化”面試官通常都會對這個層面的經(jīng)驗印象很深。2. 拆與不拆單體到微服務(wù)的第一道選擇題微服務(wù)幾乎是Java后端面試的必聊話題但聊的方向往往跑偏。太多人一上來就講“我們用了Nacos注冊了幾個服務(wù)、用了OpenFeign互相調(diào)用”——面試官真正想聽的其實是“你憑什么決定拆、拆到什么粒度、付出什么代價”。這一問能篩掉相當一批只知道堆名詞的候選人。2.1 微服務(wù)的隱形成本清單絕大多數(shù)人只看到微服務(wù)帶來的“好處”獨立部署、獨立擴展、技術(shù)棧異構(gòu)、團隊自治。但面試官問“微服務(wù)的缺點”時能說出幾條的候選人很少。我建議把成本清單背到滾瓜爛熟網(wǎng)絡(luò)通信成本一次本地方法調(diào)用變成遠程調(diào)用延遲從微秒級跳到毫秒級還引入了網(wǎng)絡(luò)抖動和超時處理。數(shù)據(jù)一致性代價單體里一個本地事務(wù)能搞定的事情拆開后需要分布式事務(wù)方案兜底復雜度成倍增加。運維復雜度的上升微服務(wù)數(shù)量上來后部署、監(jiān)控、日志、鏈路追蹤都要配套建設(shè)否則線上出了故障連“哪個服務(wù)先掛”都定位不到。團隊協(xié)作成本接口契約、版本兼容、發(fā)布協(xié)調(diào)每一項都需要額外管理。所以完整的回答框架應(yīng)該是微服務(wù)不是銀彈它的本質(zhì)是“用復雜度換自由度”。只有在單體確實撐不住或者團隊規(guī)模大到無法在一個工程內(nèi)協(xié)作時拆分才是理性的。面試時能說出這句話比背十篇微服務(wù)最佳實踐都管用。2.2 決定拆分粒度的四個判斷維度拆多細才算合適沒有放之四海而皆準的數(shù)字但有一套判斷框架可以從四個維度交叉驗證第一變更頻率。兩個模塊如果總是“同一次版本迭代中一起改動”說明它們之間的耦合還很緊拆開的收益不大如果用戶模塊長期單獨變更而商品模塊完全不跟它聯(lián)動那這個邊界就是天然的拆分點。第二團隊邊界。團隊的組織結(jié)構(gòu)會反過來塑造技術(shù)架構(gòu)。一個服務(wù)如果有兩個團隊同時在改溝通成本和發(fā)布沖突就會顯著上升。反過來說如果你能保證某個團隊完全自治地負責某個服務(wù)那這個服務(wù)就是值得拆的。第三數(shù)據(jù)邊界。這是最容易被忽略、也最容易拆出事故的一個維度。如果兩張表之間需要強實時的事務(wù)一致性比如訂單表和庫存表那無論業(yè)務(wù)概念上它們屬于什么中心都不該在早期拆到兩個獨立服務(wù)里。強一致需求一旦跨了物理服務(wù)邊界后續(xù)所有方案都會變得被動。第四失敗隔離。支付模塊、登錄模塊這類穩(wěn)定性要求很高的部分適合拆出去做獨立容錯低頻、可以接受長尾延遲的模塊則沒必要為“獨立”付出額外成本。面試舉例子時可以拿“訂單和庫存”來當反例很多面試者覺得這倆天然該拆成兩個服務(wù)但事實上訂單扣減庫存是最典型的“需要跨Service事務(wù)或最終一致方案”的場景也是拆得不好就要回滾重來的深淵之一。正確的拆分策略往往是先把一些邊界清晰、變更獨立、數(shù)據(jù)天然隔離的模塊拆出去而不是一上來就動核心交易鏈路。2.3 推薦的拆分順序與一次穩(wěn)妥的落地路徑如果面試官追問“如果現(xiàn)在讓你來主導一次單體到微服務(wù)的改造你會按什么順序做”最穩(wěn)妥的回答不是“全面開花”而是分四步漸進第一步先做模塊化單體。在代碼層面按業(yè)務(wù)邊界重新組織包結(jié)構(gòu)把功能邊界卡出來但還保持單一應(yīng)用、單一數(shù)據(jù)源。這一步的低成本之處在于隨時可以回退卻能驗證“業(yè)務(wù)邊界是否真的清晰”。第二步做接口解耦。讓模塊之間只通過明確的接口或者事件交互禁止跨模塊直接操作內(nèi)部數(shù)據(jù)結(jié)構(gòu)。這是為了讓之后的物理隔離不打回原形。第三步拆數(shù)據(jù)庫。數(shù)據(jù)庫拆分是最危險的一步某種程度上比拆應(yīng)用更危險。一旦數(shù)據(jù)源拆分原本的本地事務(wù)就沒了所以這一步必須配合最終的冪等、對賬和補償機制設(shè)計。第四步再拆部署單元。當一個模塊的代碼邊界、數(shù)據(jù)邊界、接口契約都驗證穩(wěn)定后最后把它的部署實例獨立出來完成真正的服務(wù)化改造。我在實際中見過太多團隊上來就復制一份代碼、拆完數(shù)據(jù)庫立刻翻車原因就是把“部署拆分”當成了第一步。順著上面這個順序做每一步都有明確的前置條件風險是可控的。3. 注冊中心與調(diào)用鏈微服務(wù)面試中最穩(wěn)的送分題如果說自動配置是Spring Boot的必問題那注冊中心和遠程調(diào)用就是微服務(wù)模塊的必問題。這塊內(nèi)容其實并不難但它特別能檢驗“你到底是看過原理還是只背過面試題”。3.1 AP還是CP注冊中心選型的一句話答案面試官通常拋出的是“Eureka、ZooKeeper、Nacos、Consul你怎么選它們的區(qū)別是什么”這道題的實質(zhì)是分布式領(lǐng)域最基礎(chǔ)的CAP理論在真實系統(tǒng)里的體現(xiàn)。CAP不可能三角——一致性、可用性、分區(qū)容錯性——在分布式系統(tǒng)中只能三選二而分區(qū)是必然的所以我們實際是在AP和CP之間做取舍。把這個理論落地到注冊中心場景里Eureka典型AP。它即使發(fā)現(xiàn)某個實例心跳超時也不會立即從注冊列表里剔除因為怕網(wǎng)絡(luò)抖動導致誤殺這個設(shè)計叫“自我保護模式”。犧牲的代價是可能讓調(diào)用方拿到一些已經(jīng)事實上不可用的實例地址。ZooKeeper典型CP。寫入必須獲得多數(shù)節(jié)點確認leader發(fā)生故障時集群會短暫不可用要等重新選舉完成。它適合作為分布式鎖等強一致元數(shù)據(jù)的底座。Nacos比較靈活默認AP模式支持切換成CP模式。它用Distro協(xié)議做AP用Raft做CP可以按場景調(diào)整。Consul基于Raft協(xié)議屬于CP?;卮鹜昴P筒町愐欢ㄒa上更關(guān)鍵的一句取舍邏輯服務(wù)注冊中心本質(zhì)上允許“臟數(shù)據(jù)”短暫存在拿到一個壞節(jié)點重試另一個即可但絕對不允許注冊中心本身長時間不可用那會導致所有服務(wù)互相找不到整個調(diào)用鏈雪崩。所以工程實踐上注冊中心更傾向于選AP。而像分布式鎖這類要求“同一時刻只有一個客戶端拿到鎖”的強一致場景必須用CP。3.2 超時、重試、熔斷服務(wù)調(diào)用的三板斧注冊中心解決的是“找到服務(wù)”找到之后的“安全調(diào)用”是另一個高頻拷問點。面試官可能會拋出這樣的場景“一個服務(wù)依賴另一個服務(wù)現(xiàn)在下游變慢了你怎么保護上游以及怎么防止故障蔓延”核心答案可以濃縮成三條超時、重試、熔斷。先說超時。很多初級工程師只設(shè)一次超時比如HTTP連接超時3秒就完事但一個嚴謹?shù)恼{(diào)用必須分開設(shè)置連接超時和讀超時。連接超時通常短一些一兩秒就夠讀超時則要結(jié)合下游接口的P99耗時而定不能盲目給一個很大的數(shù)。如果讀超時給到30秒下游一旦卡住上游線程池很快就會被拖垮。再說重試。原則只有一句只有冪等的接口才允許自動重試。非冪等接口重試會造成重復下單、重復扣款等事故。即使重試也必須加重試上限并配合指數(shù)退避比如第一次隔100毫秒、第二次隔200毫秒、第三次隔400毫秒而不是瘋狂打下游把一個小故障放大成雪崩。最后是熔斷。熔斷器的思想可以用家里的保險絲類比當錯誤率超過閾值時開關(guān)直接打開后續(xù)請求快速失敗不再繼續(xù)阻塞等待下游。熔斷器有三種狀態(tài)關(guān)閉正常調(diào)用、打開快速失敗、半開放少量試探請求看下游是否恢復。半開狀態(tài)下如果試探成功熔斷器從打開轉(zhuǎn)回關(guān)閉整個系統(tǒng)就恢復到正常工作狀態(tài)。還有一個跟熔斷經(jīng)?;煸谝黄鸬母拍钍恰敖导墶?。它們的關(guān)系用一句話講清楚熔斷是“我判斷下游不行了快速失敗避免拖垮自己”降級是“我拿一個兜底結(jié)果替代真實調(diào)用”。比如推薦服務(wù)掛了商品詳情頁可以降級為返回默認推薦列表保證頁面整體能用。3.3 負載均衡與網(wǎng)關(guān)的常見追問服務(wù)調(diào)用不止直連一個節(jié)點負載均衡和網(wǎng)關(guān)也是繞不開的。Spring Cloud環(huán)境下常問的負載均衡策略包括輪詢、隨機、最少并發(fā)數(shù)、加權(quán)響應(yīng)時間等。如果要自定義核心是在LoadBalancer新版Spring Cloud廢棄了Ribbon里實現(xiàn)一個ServiceInstanceListSupplier把“給哪個實例發(fā)請求”的決策權(quán)拿回自己手里?;卮疬@個時順帶點一句“為什么需要服務(wù)端健康檢查配合”比單獨背策略列表有深度得多。網(wǎng)關(guān)方面Spring Cloud Gateway已經(jīng)成為主流它基于WebFlux實現(xiàn)非阻塞方式處理請求性能和資源占用優(yōu)于老的Zuul 1.x。常問的還有網(wǎng)關(guān)與注冊中心的集成網(wǎng)關(guān)通過注冊中心拿到服務(wù)列表之后按路由規(guī)則把請求轉(zhuǎn)發(fā)到對應(yīng)服務(wù)天然支持了統(tǒng)一的入口、鑒權(quán)、限流和日志采集。如果面試官繼續(xù)追問“網(wǎng)關(guān)和Nginx有什么區(qū)別”可以答Nginx更側(cè)重四層和七層流量入口Spring Cloud Gateway更貼近業(yè)務(wù)容器內(nèi)部做更細粒度的路由、鑒權(quán)和過濾。4. 分布式事務(wù)與冪等最容易暴露“沒上線經(jīng)驗”的深水區(qū)微服務(wù)面試真正的分水嶺通常出現(xiàn)在分布式事務(wù)相關(guān)的問題上。因為這玩意不是看了博客就會的它需要踩過坑、寫過對賬腳本、處理過線上臟數(shù)據(jù)才能真正理解每個方案背后的取舍。4.1 面試不再只問概念更多在問適用性關(guān)于方案概念本身面試前至少要達到“脫口而出能說清機制”的程度2PC兩階段提交協(xié)調(diào)者先問所有參與者“能不能提交”都同意后再統(tǒng)一提交。好處是強一致壞處是阻塞式協(xié)議協(xié)調(diào)者一旦掛了參與者會一直處在鎖定狀態(tài)性能和可用性都比較糟糕。XA事務(wù)就是它的落地形態(tài)。TCC從業(yè)務(wù)層面把提交過程拆成Try、Confirm、Cancel三步。Try階段預留業(yè)務(wù)資源比如扣減預占庫存Confirm階段真正執(zhí)行Cancel階段回滾。它的優(yōu)點是相對高性能缺點是對業(yè)務(wù)代碼侵入很重而且每個動作都要寫好補償邏輯。SAGA把一個長事務(wù)拆成一個個本地事務(wù)中間失敗的話往前逐個執(zhí)行反向補償操作。適合跨多個服務(wù)的長時間業(yè)務(wù)流程比如訂機票訂酒店這種場景。本地消息表把“業(yè)務(wù)操作”和“寫消息表”放在同一個本地事務(wù)里然后由后臺任務(wù)把消息表里的記錄投遞給MQ消費者消費成功后再刪除或標記消息。這是很多團隊實際用的方案簡單可靠。消息事務(wù)半消息模式以RocketMQ為代表先發(fā)一條半消息事務(wù)執(zhí)行成功后再確認提交失敗則回滾。解決了“先發(fā)消息后業(yè)務(wù)失敗”的經(jīng)典難題。然而面試能不能過關(guān)鍵不在于你能不能把上述方案背全而在于你能不能根據(jù)場景選型。面試官如果追問“你們系統(tǒng)里為什么用這個方案”你要能給出“場景逼著我不這么選不行”的邏輯而不是“大家都這么用我就這么用”。4.2 冪等是分布式事務(wù)的前置條件有經(jīng)驗的工程師會把“冪等”掛在嘴邊因為它是分布式系統(tǒng)一致性問題的地基。面試官特別喜歡用一個場景來考MQ消費者收到消息執(zhí)行完業(yè)務(wù)了還沒提交消費位點消費者進程崩了消息被重新投遞這時候如果業(yè)務(wù)再次執(zhí)行會發(fā)生什么答案就是重復執(zhí)行。如果不做冪等保護就會出現(xiàn)庫存重復扣減、短信重復發(fā)送、積分重復累加。實現(xiàn)冪等有幾種常見方案數(shù)據(jù)庫唯一約束利用訂單號、流水號等唯一鍵讓數(shù)據(jù)庫攔截重復插入。Token機制前端提交時帶一個唯一標識服務(wù)端處理完保存token再次提交直接忽略。狀態(tài)機校驗比如訂單從“待支付”到“已支付”只允許單向流轉(zhuǎn)重復的支付回調(diào)如果發(fā)現(xiàn)當前狀態(tài)已經(jīng)是“已支付”直接返回成功不再重復改庫。樂觀鎖版本號更新時帶上versionWHERE version ?影響行數(shù)為0則說明已被別的請求處理過。有一個特別容易忽略的坑冪等并不只能靠數(shù)據(jù)庫唯一鍵如果業(yè)務(wù)處理邏輯里包含外部調(diào)用外部系統(tǒng)那邊的接口也必須支持冪等否則你在自己這邊防住了下游還是掛了。所以面試時如果能主動說出這句話就能展現(xiàn)出真正的全局視角。4.3 如何用“場景驅(qū)動”組織回答“你們用了分布式事務(wù)嗎”這個問題最忌諱直接回答“用了”或者“沒用”。一次有價值的回答應(yīng)該是拼圖的先一句話說明場景。比如“在訂單創(chuàng)建和庫存扣減這個鏈路里我們允許最終一致所以沒有引入強一致事務(wù)方案?!比缓蠼忉尀槭裁床荒苡?PC——因為下單高峰期對可用性要求很高2PC的阻塞式設(shè)計扛不住。再講用的是什么方案——“我們選擇了本地消息表或者RocketMQ事務(wù)消息先把訂單落庫再把扣庫存消息可靠地發(fā)出去配合消費端的冪等處理最終達到一致性?!边@個回答鏈條里包含了場景、取舍、機制、容錯四個方面面試官很容易據(jù)此判斷你是有真實架構(gòu)經(jīng)驗的人而不是背概念的候選人。5. 收尾階段的高頻追問如何展現(xiàn)工程經(jīng)驗而不是背誦聊到這里一場Java后端面試的硬核部分其實已經(jīng)接近尾聲。接下來面試官通常會問一些開放式問題來驗證你前面講的內(nèi)容是“自己消化過的”還是“臨時背下來的”。這類題沒有標準答案但回答思路很關(guān)鍵。5.1 用STAR方式講“線上故障”案例“你線上遇到過最深刻的問題是什么”這個問題出現(xiàn)頻率極高。我建議回答時套用STAR結(jié)構(gòu)背景Situation—任務(wù)Task—行動Action—結(jié)果Result。不要直接奔著“我解決了問題”去講要把定位問題的過程展現(xiàn)出來因為面試官想看的是你的排查鏈路。舉個例子我處理過一個自動配置相關(guān)的真實故障正好可以套進來一次新環(huán)境上線后應(yīng)用出現(xiàn)大量慢SQL和Redis連接數(shù)被打滿的現(xiàn)象。剛開始大家懷疑是流量突增看了監(jiān)控才發(fā)現(xiàn)是連接集中在少數(shù)熱點節(jié)點上。順著“為什么連接分配這么不均勻”往下查發(fā)現(xiàn)某服務(wù)里自定義了一個負載均衡策略但沒有遵守“按存活實例過濾”的前提導致大量請求被路由到已經(jīng)不健康的實例上超時重試又放大了流量。最終修復是在自定義策略里先過濾掉不健康實例再按權(quán)重分配并用壓測驗證了恢復效果。這個案例里包含的現(xiàn)象描述、鏈路排查、根因定位和修復驗證能讓面試官直觀感受到“這個人是真的上過線、處理過真實故障的人”。即使你沒有類似分布式故障的經(jīng)歷用自己做過的最復雜的排障案例套用這個結(jié)構(gòu)也比泛泛講“我精通XX技術(shù)”好得多。5.2 現(xiàn)場手寫一個令牌桶限流器面試最后如果還有十分鐘面試官偶爾會出“手寫一個簡單限流器”這種題考驗編碼基本功和工程意識。令牌桶是我最推薦提前準備的版本因為它的思想最容易在幾分鐘內(nèi)寫出來又能順帶講解為什么它比固定窗口限流更適合突發(fā)流量。令牌桶的核心邏輯是系統(tǒng)以恒定速率往桶里放令牌請求來了需要先拿到令牌才能放行桶能容納的令牌有上限所以瞬間突發(fā)流量最多只能消耗掉桶里預存的令牌數(shù)。實現(xiàn)時不需要真的起一個定時任務(wù)而是利用“計算自上次請求以來補充了多少令牌”來模擬速率public class TokenBucketRateLimiter { private final long capacity; private final long refillRatePerSecond; private double tokenCount; private long lastRefillTime; public TokenBucketRateLimiter(long capacity, long refillRatePerSecond) { this.capacity capacity; this.refillRatePerSecond refillRatePerSecond; this.tokenCount capacity; this.lastRefillTime System.currentTimeMillis(); } public synchronized boolean tryAcquire() { long now System.currentTimeMillis(); long elapsed now - lastRefillTime; double tokensToAdd elapsed * refillRatePerSecond / 1000.0; tokenCount Math.min(capacity, tokenCount tokensToAdd); lastRefillTime now; if (tokenCount 1) { tokenCount - 1; return true; } return false; } }寫完之后再跟面試官補一句“這里我用synchronized保證并發(fā)安全生產(chǎn)環(huán)境下可以用AtomicLong或者鎖分段來降低競爭”——這句話可以很自然地展示出你思考過并發(fā)場景。也可以繼續(xù)問一句“漏桶和令牌桶的區(qū)別”然后補充漏桶控制的是流出速率請求是平滑出去的令牌桶允許桶內(nèi)積攢的令牌被一次性消耗所以允許一定程度的突發(fā)流量。5.3 手寫代碼題的兩條實戰(zhàn)心得最后分享兩條我在面試和真實工作中都驗證過的心得。第一代碼題寧可先寫“能跑但不能并發(fā)”的版本也比一開始追求完美導致寫不出來強。面試官看先看思路再看完整度。你甚至在動筆前就可以說“我先用最簡單的方式實現(xiàn)再討論并發(fā)優(yōu)化方案?!边@個動作本身已經(jīng)展現(xiàn)了工程上的迭代思維。第二面試答技術(shù)問題時永遠要先給結(jié)論、再給原因、最后給場景。比如說到自動配置先一句話說“從配置文件中讀取自動配置類經(jīng)過條件判斷后決定是否生效”再展開細節(jié)。很多候選人恰好反過來繞了半天細節(jié)最后也沒總結(jié)出結(jié)論面試官聽著費力分數(shù)自然打不高。