崗面經(jīng):交通銀行與微眾銀行,從基礎(chǔ)八股到分布式實戰(zhàn))
每年秋招春招最難熬的不是投簡歷而是面試。投出去幾十份簡歷等來的面試機(jī)會就那么幾個每一個都值得認(rèn)真對待。我去年秋招的時候面了交通銀行和微眾銀行兩家都走到了終面最后拿了其中一家的offer。當(dāng)時我把面試題和答案整理成了一份文檔陸陸續(xù)續(xù)分享給幾個學(xué)弟學(xué)妹反饋都說幫助很大。今天把這份面經(jīng)完整整理出來題目和答案都做了補(bǔ)充希望能幫到正在準(zhǔn)備銀行系或者互聯(lián)網(wǎng)銀行面試的同學(xué)。這篇面經(jīng)不是簡單的題目羅列而是把每道題背后的考察點(diǎn)、我當(dāng)時是怎么答的、哪些地方答得不好、后來復(fù)盤怎么補(bǔ)上都寫清楚了。不管你是準(zhǔn)備Java后端還是打算投銀行的技術(shù)崗這份內(nèi)容都有參考價值。交通銀行是傳統(tǒng)國有大行的風(fēng)格微眾銀行是互聯(lián)網(wǎng)銀行的風(fēng)格兩家面試的側(cè)重點(diǎn)差別挺大對比著看你就能明白不同公司到底想招什么樣的人。1. 面試前的準(zhǔn)備先搞清兩家銀行的定位很多同學(xué)準(zhǔn)備面試喜歡一上來就刷八股文其實順序反了。你得先搞清楚這家公司到底要什么樣的人再決定怎么準(zhǔn)備。交通銀行和微眾銀行雖然都叫銀行但技術(shù)面試的風(fēng)格可以說是兩個極端。1.1 交通銀行的面試風(fēng)格與考察重點(diǎn)交通銀行作為國有大行技術(shù)面試的風(fēng)格偏傳統(tǒng)考察的內(nèi)容非常基礎(chǔ)基本圍繞Java核心技術(shù)棧、數(shù)據(jù)庫、計算機(jī)基礎(chǔ)展開。面試官不太會問你用過什么特別新潮的框架反而會抓住一個知識點(diǎn)往深里問比如HashMap的擴(kuò)容機(jī)制、JVM的內(nèi)存模型、MySQL索引的底層結(jié)構(gòu)這些。還有一個很明顯的感受交通銀行的面試流程相對固定一面和二面的內(nèi)容區(qū)分度不大都是以技術(shù)基礎(chǔ)為主。面試官的態(tài)度普遍比較溫和與其說是考察你不如說是在確認(rèn)你是否具備扎實的計算機(jī)功底。這種風(fēng)格的好處是只要基礎(chǔ)夠硬答起來會比較有底氣。1.2 微眾銀行的面試風(fēng)格與考察重點(diǎn)微眾銀行雖然是銀行牌照但本質(zhì)上是一家互聯(lián)網(wǎng)公司技術(shù)面試的風(fēng)格跟大廠非常接近。一面就會上算法題而且是需要你在白板上寫代碼那種。考察的內(nèi)容里分布式、高并發(fā)、緩存、消息隊列這些占了很大比重還會深挖你項目里的技術(shù)難點(diǎn)問到你答不上來為止。我在微眾的面試中明顯感覺到面試官非??粗睾蜻x人解決實際問題的能力。同樣的知識點(diǎn)他不會問你“Redis有哪些數(shù)據(jù)結(jié)構(gòu)”而是會問“在高并發(fā)場景下你用Redis的哪種數(shù)據(jù)結(jié)構(gòu)解決什么問題為什么選它”。這種問法光背八股文是過不了關(guān)的。1.3 我的準(zhǔn)備策略我當(dāng)時的時間安排是這樣的前兩周集中刷Java基礎(chǔ)和數(shù)據(jù)庫的八股文每個知識點(diǎn)都整理成自己的話術(shù)后兩周刷LeetCode熱題和復(fù)習(xí)項目。項目復(fù)盤是重中之重我把項目里每一個技術(shù)選型的原因、遇到的坑、最終效果都重新過了一遍確保面試官隨便問哪個點(diǎn)都能展開說。準(zhǔn)備面試有一個特別實用的方法就是對著鏡子或者錄音練習(xí)。你以為自己懂了說出來才發(fā)現(xiàn)邏輯是亂的。我當(dāng)時把高頻題的答案都寫成稿子反復(fù)錄音、回聽、修改直到能流暢自然地講出來。這個習(xí)慣幫我避免了很多“腦子懂了但嘴說不出來”的尷尬。2. 交通銀行面經(jīng)實錄基礎(chǔ)扎實比花活重要交通銀行的面試整體氛圍比較輕松一面和二面都是技術(shù)面但考察的深度差別不大。我遇到的面試官很友善答錯了他還會引導(dǎo)你往正確的方向想。下面把還記得的題目和我的答題思路整理出來。2.1 一面核心八股題答案HashMap的底層實現(xiàn)、put流程和擴(kuò)容機(jī)制。這道題幾乎是必考題。我從JDK1.8的數(shù)組鏈表紅黑樹結(jié)構(gòu)說起put時的hash計算key的hashCode高低16位異或、遇到哈希沖突時怎么掛鏈表、鏈表長度超過8且數(shù)組長度超過64時樹化、擴(kuò)容時為什么是2倍冪為了哈希均勻和位運(yùn)算優(yōu)化。答這道題的關(guān)鍵是要有層次先數(shù)據(jù)結(jié)構(gòu)再流程再優(yōu)化考慮面試官想聽到的是你是否真的理解而不是背誦。JVM的內(nèi)存區(qū)域劃分和垃圾回收算法。我把堆、虛擬機(jī)棧、本地方法棧、方法區(qū)、程序計數(shù)器逐個說明重點(diǎn)講了堆的分代新生代、老年代、Minor GC和Full GC的區(qū)別以及可達(dá)性分析算法里GC Roots包含哪些對象。面試官追問了CMS和G1的區(qū)別我答了CMS是標(biāo)記-清除算法、會產(chǎn)生碎片、G1是Region劃分、可預(yù)測停頓時間這些是JVM調(diào)優(yōu)里最基本的常識。MySQL的索引底層為什么用B樹。這道題我給出的核心思路是二叉搜索樹會退化成鏈表AVL樹旋轉(zhuǎn)太頻繁紅黑樹層高還是不夠低B樹雖然矮但非葉子節(jié)點(diǎn)也存數(shù)據(jù)導(dǎo)致單節(jié)點(diǎn)能存儲的索引數(shù)量少B樹非葉子節(jié)點(diǎn)只存索引、葉子節(jié)點(diǎn)形成有序鏈表更適合范圍查詢和磁盤預(yù)讀。面試官對每個點(diǎn)都追問了“為什么”說明他真的想確認(rèn)你是不是理解了這些數(shù)據(jù)結(jié)構(gòu)的差異。Spring的IOC和AOP原理。IOC我講了BeanFactory和ApplicationContext的關(guān)系、Bean的生命周期實例化、屬性填充、初始化、銷毀AOP講了動態(tài)代理的兩種方式JDK代理和CGLIB代理以及各自的適用條件。這里有個坑一定要說清楚“Spring中默認(rèn)對實現(xiàn)了接口的類使用JDK代理對沒實現(xiàn)接口的類使用CGLIB”很多同學(xué)只說代理模式?jīng)]說清楚Spring具體怎么選的。事務(wù)的隔離級別和MVCC機(jī)制。四個隔離級別讀未提交、讀已提交、可重復(fù)讀、串行化分別解決什么問題這一點(diǎn)要能倒背如流。MySQL默認(rèn)是可重復(fù)讀但也沒有徹底解決幻讀問題需要配合間隙鎖。MVCC的機(jī)制我講了三張隱式字段DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID、undo log版本鏈和ReadView的可見性判斷規(guī)則。2.2 二面場景題與項目深挖二面的面試官明顯級別更高問的問題更偏向場景和項目但還是沒有離開基礎(chǔ)知識的范疇。緩存穿透、緩存擊穿、緩存雪崩如何解決。這道題我們項目里真實遇到過所以答得比較順。穿透我回答的是布隆過濾器緩存空值擊穿是熱點(diǎn)key加互斥鎖或邏輯過期雪崩是過期時間加隨機(jī)值多級緩存服務(wù)降級。面試官追問了一個點(diǎn)布隆過濾器誤判怎么辦我回答可以定期重建布隆過濾器或者對誤判的key做二次校驗雖然追問很細(xì)但思路對了基本沒問題。高并發(fā)下的訂單超賣問題。這是一道經(jīng)典的數(shù)據(jù)庫題目。我給出的是樂觀鎖方案更新時加版本號或庫存條件UPDATE ... WHERE stock 0如果影響行數(shù)為0則說明庫存不足。面試官又問能不能用Redis扣減庫存我說可以但要注意Redis和數(shù)據(jù)庫的一致性用Lua腳本保證原子性。這道題的核心是讓面試官看到你有明確的方案對比意識而不是只會背一種解法。介紹項目里最有挑戰(zhàn)性的一個點(diǎn)。這個一定要提前準(zhǔn)備不能現(xiàn)場想。我講的是項目里的一個消息推送服務(wù)延遲高峰期會積壓大量消息。我的方案是改成批量消費(fèi)動態(tài)線程池的參數(shù)調(diào)整最終把消費(fèi)吞吐提升了3倍。面試官的關(guān)注點(diǎn)在于問題是怎么發(fā)現(xiàn)的監(jiān)控、方案是怎么驗證的灰度、最后效果怎么量化QPS、延遲數(shù)據(jù)。你在準(zhǔn)備項目時一定把這三個問題想清楚。2.3 交通銀行的避坑心得交通銀行的面試題目本身不算難但有一個容易忽略的點(diǎn)他們非??粗乇磉_(dá)的條理性。同一個答案有人能拿高分有人只能及格差別就在表達(dá)方式。我的建議是回答任何技術(shù)問題都用“先說結(jié)論、再講原理、最后舉例子”的結(jié)構(gòu)這能讓面試官快速get到你的思路。還有一個小細(xì)節(jié)交通銀行的一面和二面之間隔了挺久期間最好主動跟進(jìn)一下狀態(tài)表現(xiàn)你對這個崗位的誠意。我當(dāng)時是二面結(jié)束后兩周才收到的通知期間心態(tài)有一點(diǎn)點(diǎn)崩但事實證明只要面試發(fā)揮到位流程慢一點(diǎn)是正常的不用自己嚇自己。3. 微眾銀行面經(jīng)實錄算法與項目深度是分水嶺微眾銀行的面試強(qiáng)度明顯上了一個臺階。一面就有兩道手撕代碼題二面對項目的追問非常深幾乎每個技術(shù)點(diǎn)都要問到你“為什么這樣選”。如果之前沒經(jīng)歷過互聯(lián)網(wǎng)風(fēng)格的面試可能會有點(diǎn)不適應(yīng)。3.1 一面算法題與Java基礎(chǔ)算法題實現(xiàn)一個LRU緩存。這道題是LeetCode 146的原題我用HashMap雙向鏈表實現(xiàn)的get和put都是O(1)復(fù)雜度。寫完之后面試官問了一個問題為什么不用LinkedHashMap我說LinkedHashMap底層就是HashMap雙向鏈表原理一樣自己實現(xiàn)是為了展示對數(shù)據(jù)結(jié)構(gòu)的掌握。這個回答讓面試官比較滿意。寫算法題的時候一定要邊說邊寫把自己的思路同步給面試官沉默著寫完是最吃虧的。算法題給定一個數(shù)組找出其中第K大的數(shù)。我給出了兩種解法快排partition法和堆法。面試官追問了時間復(fù)雜度和空間復(fù)雜度以及大數(shù)據(jù)量下比如10億個數(shù)應(yīng)該怎么處理。大數(shù)據(jù)量下堆法更優(yōu)因為只需要維護(hù)一個大小為K的小頂堆空間復(fù)雜度是O(K)而快排partition需要把所有數(shù)加載到內(nèi)存。能答出這個對比面試官才會認(rèn)為你真的理解了。Java基礎(chǔ)ConcurrentHashMap的實現(xiàn)原理。我講了JDK1.8的CASsynchronized實現(xiàn)put時對node節(jié)點(diǎn)加鎖相比JDK1.7的Segment分段鎖粒度更細(xì)鎖競爭更小。面試官追問了size()方法是怎么實現(xiàn)的我回答了通過baseCount和CounterCell數(shù)組來避免競爭必要時加鎖。這道題屬于Java并發(fā)編程的高頻題一定要吃透。Java基礎(chǔ)線程池的參數(shù)和拒絕策略。七大參數(shù)核心線程數(shù)、最大線程數(shù)、存活時間、時間單位、工作隊列、線程工廠、拒絕策略必須背熟四種拒絕策略AbortPolicy、CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy要能解釋清楚。面試官問了一個實戰(zhàn)場景核心線程數(shù)是4最大線程數(shù)是8隊列容量是100同時來了200個任務(wù)會發(fā)生什么我當(dāng)時有點(diǎn)緊張算錯了后來復(fù)盤才發(fā)現(xiàn)第105個任務(wù)開始才會觸發(fā)拒絕策略。3.2 二面分布式與項目難點(diǎn)二面的面試官是技術(shù)主管全程沒有問八股文全部圍繞項目和他的技術(shù)棧展開。分布式鎖的場景和實現(xiàn)方式。我們項目里有一個庫存扣減的場景為了保證多實例下不超賣我用過Redis的SETNX實現(xiàn)分布式鎖后來發(fā)現(xiàn)鎖可能過期導(dǎo)致業(yè)務(wù)還沒執(zhí)行完鎖就被釋放了改成Redisson的看門狗機(jī)制自動續(xù)期。面試官繼續(xù)追問如果Redis主節(jié)點(diǎn)宕機(jī)鎖丟失怎么辦我說可以用RedLock但面試官明顯對這個方案有保留意見后來我了解到RedLock本身在業(yè)界就有爭議這種情況下最好的回答是承認(rèn)這個方案的局限性然后說明自己做過哪些權(quán)衡。RocketMQ和Kafka的選型對比。我說項目里用的是RocketMQ因為公司技術(shù)棧本身偏向阿里系。面試官問如果讓你重新選你會怎么選我的回答是如果對消息順序和事務(wù)消息有強(qiáng)要求選RocketMQ如果追求超高吞吐量選Kafka兩者在功能上有重疊但適合的場景不同。這種開放性的問題面試官想聽的是你的判斷依據(jù)而不是標(biāo)準(zhǔn)答案。設(shè)計一個秒殺系統(tǒng)。這是一個經(jīng)典的架構(gòu)設(shè)計題。我從四個方面展開流量控制通過驗證碼、答題、CDN靜態(tài)化來降低請求量、庫存扣減Redis預(yù)扣減Lua保證原子性異步同步數(shù)據(jù)庫、防刷同一個用戶限購、IP限流、降級超過閾值直接返回失敗。面試官在每個環(huán)節(jié)都追問了細(xì)節(jié)尤其是Redis和數(shù)據(jù)庫的一致性說明他非常關(guān)心方案能不能落地。3.3 微眾銀行的避坑心得微眾銀行的面試最大的坑就是算法題。如果你平時刷題量不夠一面的兩道題可能就會卡住。我的經(jīng)驗是高頻題LRU、TopK、反轉(zhuǎn)鏈表、最長回文子串、三數(shù)之和一定要刷到滾瓜爛熟能默寫的程度。面試的時候不要糾結(jié)最優(yōu)解先給出一個可運(yùn)行的暴力解再和面試官討論優(yōu)化這樣至少不會零分。另外一個心得是微眾的面試官很吃“業(yè)務(wù)理解”這一套。同樣一道分布式鎖的題你只說技術(shù)方案和你說“我們業(yè)務(wù)場景里商品庫存只有幾千個并發(fā)量不算極端所以用Redis就夠了不需要引入ZooKeeper”面試官的反應(yīng)是完全不一樣的。讓面試官看到你有結(jié)合業(yè)務(wù)做技術(shù)決策的意識這是互聯(lián)網(wǎng)風(fēng)格面試的核心。4. 兩家銀行面經(jīng)答案里的通用考點(diǎn)清單面完這兩家銀行之后我把所有的題目做了個歸類發(fā)現(xiàn)高頻考點(diǎn)其實是趨同的。不管面試官換什么問法核心知識點(diǎn)就那么幾個。下面整理一個速查表對著這個表復(fù)習(xí)效率會高很多。4.1 高頻八股題速查表考點(diǎn)核心要點(diǎn)常見問法HashMap數(shù)組鏈表紅黑樹擴(kuò)容2倍冪線程不安全底層結(jié)構(gòu)、put流程、為什么用紅黑樹ConcurrentHashMapCASsynchronized鎖粒度細(xì)化和Hashtable的區(qū)別、size()實現(xiàn)JVM內(nèi)存堆、棧、方法區(qū)、程序計數(shù)器內(nèi)存區(qū)域劃分、哪些是線程共享GC算法標(biāo)記-清除、標(biāo)記-復(fù)制、標(biāo)記-整理CMS和G1的區(qū)別、如何選擇垃圾收集器MySQL索引B樹、聚簇索引、回表為什么用B樹、索引失效場景事務(wù)隔離四種隔離級別、MVCC、間隙鎖可重復(fù)讀解決了什么、幻讀怎么處理Redis數(shù)據(jù)結(jié)構(gòu)、持久化、緩存雪崩/穿透/擊穿緩存一致性怎么保證消息隊列選型對比、消費(fèi)冪等、順序消費(fèi)怎么保證消息不丟失SpringIOC、AOP、Bean生命周期循環(huán)依賴怎么解決分布式CAP理論、分布式鎖、BASE分布式事務(wù)有哪些方案這張表覆蓋了80%以上的面試題前提是你真能把這些點(diǎn)展開講清楚而不是看一眼覺得“哦我知道”就過了。我吃了很多虧才明白能寫出來、能講出來才是真的會。4.2 場景題的答題框架除了八股題面試?yán)镒钆碌木褪菆鼍邦}題干通常很短比如“如果讓你設(shè)計一個X系統(tǒng)你怎么做”。這類題沒有標(biāo)準(zhǔn)答案但有一個通用的答題框架。先說業(yè)務(wù)目標(biāo)把這個系統(tǒng)要解決的核心問題講清楚比如秒殺系統(tǒng)就是要“在極高并發(fā)下還能正常賣貨”再畫一個整體架構(gòu)從接入層到應(yīng)用層到數(shù)據(jù)層逐層說明每個環(huán)節(jié)用什么組件、為什么這么選然后說關(guān)鍵難點(diǎn)高并發(fā)下的數(shù)據(jù)一致性怎么保證、熱點(diǎn)數(shù)據(jù)怎么處理、系統(tǒng)掛了怎么降級最后說權(quán)衡與取舍比如你說用Redis做庫存扣減就要承認(rèn)Redis宕機(jī)的風(fēng)險并提出補(bǔ)償方案。這個框架最大的好處是不會冷場。就算你對某個系統(tǒng)不熟悉按照“業(yè)務(wù)目標(biāo)、架構(gòu)、難點(diǎn)、取舍”的順序也能說出一些有內(nèi)容的話比憋半天說一句“我不會”強(qiáng)得多。平時可以拿“設(shè)計一個短鏈系統(tǒng)”“設(shè)計一個掃碼登錄”“設(shè)計一個延遲消息隊列”來練手每個題練兩遍面試時遇到場景題就不慌了。5. 復(fù)盤面完這兩家銀行我總結(jié)的經(jīng)驗面了這么多輪最大的感受是面試不只是公司在挑你也是你在判斷這家公司適不適合自己。交通銀行的面試讓我覺得踏實微眾銀行的面試讓我覺得刺激但都讓我更清楚自己的定位。下面是幾個我認(rèn)為最核心的經(jīng)驗。5.1 面試官到底想看什么面試官每天面那么多人記住一個人很難。能讓他寫下“通過”兩個字的往往是這個候選人有某一個點(diǎn)特別突出。要么是某個項目講得讓人印象深刻要么是一道算法題給出了漂亮的優(yōu)化要么是對某個技術(shù)有超出簡歷本身的深度理解。所以不要試圖在45分鐘里面面俱到那樣反而顯得沒有重點(diǎn)。選一個你最擅長的方向不管是JVM、Redis還是消息隊列往深了準(zhǔn)備準(zhǔn)備到面試官問什么都能接住。面試官一旦在一個方向上確認(rèn)了你的深度就會默認(rèn)你在其他方向也有類似的潛力這就是“一超帶動多強(qiáng)”。5.2 關(guān)于答案的靈活表達(dá)同一個知識點(diǎn)背出來的答案和講出來的答案面試官一聽就能分辨。我第一次模擬面試的時候被朋友指出“像在背課文”后來我才意識到背答案是因為我并沒有真正理解。調(diào)整的方法是每次復(fù)習(xí)一個知識點(diǎn)都先用自己的話復(fù)述一遍然后試著給一個完全不懂技術(shù)的人講一遍如果他能聽懂說明你是真的理解了。還有一個很實用的技巧在回答的時候多用“我當(dāng)時是這么想的”“這里有個坑是”“后來我踩過一次”這類帶個人經(jīng)歷的表述。面試本質(zhì)上是一次交流不是考試你講得越自然面試官就越放松也越愿意給你機(jī)會。5.3 一些小建議簡歷上寫的每一個項目都要準(zhǔn)備好被深挖。寫“使用了Redis”就要能回答“為什么用Redis而不是本地緩存”寫“解決了千級QPS”就要能解釋清楚這個數(shù)字怎么來的。經(jīng)不起追問的簡歷內(nèi)容就是給自己埋雷。面試前的那個晚上不要再刷題了。我當(dāng)時是把高頻題的答案錄成音頻睡前聽一遍效果比看文檔好很多。面試當(dāng)天提前20分鐘到整理一下狀態(tài)。遇到不會的題先冷靜30秒把題目復(fù)述一遍給自己爭取思考時間就算答不全也要讓面試官看到你的思考過程。最后再分享一個我踩過的坑面完試一定要記錄復(fù)盤。我當(dāng)時專門建了一個文檔每面完一場就把題目回憶出來標(biāo)注哪些答得好、哪些需要補(bǔ)課。這份文檔在后續(xù)幾場面試中幫了大忙因為它讓我清楚地知道自己的薄弱點(diǎn)在哪里也知道自己的優(yōu)勢在哪里。面經(jīng)的意義不是讓你背題而是讓你提前見過足夠多的場景真正上場的時候不慌。希望這份面經(jīng)能幫到正在準(zhǔn)備面試的你。