平臺研發(fā)筆試復(fù)盤:操作系統(tǒng)與網(wǎng)絡(luò)核心考點解析)
1. 試卷整體印象與考察邏輯先說個背景。2015年的阿里巴巴基礎(chǔ)平臺研發(fā)崗實習(xí)生招聘是我當(dāng)年參加過的最“硬核”的筆試之一。那個時期的基礎(chǔ)平臺團隊還在做阿里內(nèi)部大規(guī)模分布式存儲、消息中間件、統(tǒng)一調(diào)度系統(tǒng)這類底層基礎(chǔ)設(shè)施所以筆試題基本不摻水分不考八股文式的死記硬背而是直接奔著一個問題去的這個實習(xí)生來了之后能不能馬上看代碼、能不能理解線上系統(tǒng)崩潰時的核心邏輯、能不能在導(dǎo)師給了一堆底層源碼時讀得下去。整套試卷大概涵蓋操作系統(tǒng)、計算機網(wǎng)絡(luò)、Linux使用、C/C語言特性、數(shù)據(jù)結(jié)構(gòu)與算法、分布式系統(tǒng)常識六大塊題量不小時間壓力很明顯。我印象最深的倒不是某一道題本身而是整張卷子呈現(xiàn)出的一種態(tài)度——它不追求你把每個知識點背得多熟而是追求你在大腦疲勞的狀態(tài)下還能不能保持清晰的邏輯鏈條。比如一道看似考fork進程的題目實際上是在考你對虛擬內(nèi)存、寫時拷貝、文件描述符繼承、緩沖區(qū)刷新的綜合理解任何一個環(huán)節(jié)沒打通都會答錯。如果你現(xiàn)在準(zhǔn)備類似的崗位我的建議是別把精力花在背“面經(jīng)答案”上?;A(chǔ)平臺研發(fā)對基本功的要求是實打?qū)嵉牟僮飨到y(tǒng)、網(wǎng)絡(luò)協(xié)議、C/C內(nèi)存模型這三塊怎么強調(diào)都不過分。本文后面我就按題型和知識點兩條線展開結(jié)合我自己當(dāng)年的答題情況和后來參與校招面試看到的常見問題寫一份有實際操作價值的復(fù)盤。2. 操作系統(tǒng)考點拆解從fork到內(nèi)存管理考的都是底層機制的理解2.1 進程與線程2015年的卷子就已經(jīng)在問線程模型了操作系統(tǒng)部分的題目現(xiàn)在看起來依然是經(jīng)典。進程與線程的對比老生常談但阿里巴巴的題會多繞一層不只是問“進程和線程的區(qū)別是什么”而是給定一段多線程程序讓你分析輸出結(jié)果。這就把問題從背概念拉到了真正理解線程調(diào)度和同步機制的水平上。我記得有一類題很典型題目給你一個共享變量幾個線程分別對它做自增操作每個線程循環(huán)10000次問你最終值是多少。答案是“不確定”因為自增操作不是原子性的但如果你只答“不確定”三個字基本拿不到分——題目后面會追問為什么。這時候你需要說出三個層面第一i在底層對應(yīng)load、add、store三條指令第二這三條指令之間可能發(fā)生線程上下文切換第三由于各線程的工作內(nèi)存和主內(nèi)存之間的一致性延遲一個線程的寫入可能覆蓋另一個線程的更新。這三層說全了才算真正理解。另外一個考點是線程模型?;A(chǔ)平臺開發(fā)經(jīng)常要寫高并發(fā)服務(wù)所以線程池原理、用戶態(tài)線程與內(nèi)核態(tài)線程的映射關(guān)系這類題目出現(xiàn)的頻率很高。我當(dāng)時遇到的是關(guān)于線程庫實現(xiàn)的題考點是“一對一模型、多對一模型、多對多模型”的優(yōu)缺點對比。答題時不要只列概念要結(jié)合場景說。比如多對一模型在用戶態(tài)調(diào)度上下文切換開銷小但一個線程阻塞會讓整個進程阻塞一對一模型能利用多核但線程切換要進內(nèi)核開銷大。你能自己推導(dǎo)出這些結(jié)論比背課本強得多。2.2 虛擬內(nèi)存與分頁筆試?yán)镒钊菀妆缓雎缘碾[藏大boss虛擬內(nèi)存這部分2015年的試卷直接給了我一個下馬威。有一道題是關(guān)于頁面置換算法的考LRU。LRU本身不復(fù)雜但題目設(shè)置了一個對比給定一個頁面訪問序列分別用FIFO和LRU計算缺頁次數(shù)問你為什么LRU在有些場景下缺頁率反而比FIFO高或者一樣高。這個問題其實是在提醒你任何算法都有局部的適用條件。LRU依賴時間局部性如果程序恰好是順序掃描大數(shù)組每次訪問的頁面都是一次性的LRU和FIFO的表現(xiàn)可能差不多甚至因為LRU維護成本高而更慢。做題歸做題后來我在實際項目中理解更深了?;A(chǔ)平臺服務(wù)里內(nèi)存分配器、緩存系統(tǒng)、鎖機制處處都是“置換策略”的影子。你看Redis的近似LRU實現(xiàn)看Linux內(nèi)核的頁面回收算法本質(zhì)都是對“如何淘汰一個未來最不可能被訪問的頁面”的折中。筆試?yán)锟糒RU不只是讓你背手寫鏈表加哈希表的LRU實現(xiàn)更是看你會不會在緩存設(shè)計時考慮scan-resistance的問題。內(nèi)存對齊也是一個高頻考點?;A(chǔ)平臺研發(fā)寫底層代碼的機會多結(jié)構(gòu)體對齊直接影響內(nèi)存占用和訪問性能。2015年那道題給了個結(jié)構(gòu)體含有char、int、short等幾個字段讓你求sizeof。答案是24還是16取決于平臺和編譯選項但核心是你要明白對齊規(guī)則每個成員按自身大小對齊結(jié)構(gòu)體總大小按最大對齊數(shù)對齊。這類題容易錯在忽略了編譯器默認(rèn)的對齊策略我當(dāng)年就栽了一次所以建議你刷題時親自動手用sizeof打印驗證而不只是在紙上推導(dǎo)。2.3 進程間通信與同步問題筆試和實際工程之間的橋梁進程間通信是基礎(chǔ)平臺研發(fā)的必修課筆試題也毫不客氣。管道、共享內(nèi)存、消息隊列、信號量、socket這些IPC方式要能橫向比較。我印象里有一道判斷題問“管道是單向通信的”是否正確。這題比較基礎(chǔ)但擴展出來就有東西了管道分匿名管道和命名管道匿名管道只能用于父子進程而且默認(rèn)半雙工如果你要雙向通信得建兩個管道。這里有個細(xì)節(jié)很多人忽略——管道的數(shù)據(jù)傳輸是在內(nèi)核緩沖區(qū)中完成的大小有限制。當(dāng)時題目問的就是“管道寫端寫數(shù)據(jù)阻塞的條件”答案是緩沖區(qū)滿。你沒有真正用管道寫過大量數(shù)據(jù)很難體會這個限制。同步問題里哲學(xué)家就餐問題是必考的。2015年的題目不是讓你背信號量解法而是給出一個具體實現(xiàn)讓你指出其中可能導(dǎo)致死鎖的代碼段。這就很真實了因為實際工程里不會有人告訴你“我這里有死鎖”而是系統(tǒng)莫名其妙卡死你用gdb attach上去發(fā)現(xiàn)所有線程都在等一個永遠(yuǎn)等不到的鎖。答題思路要清晰死鎖的四個必要條件——互斥、持有并等待、非搶占、循環(huán)等待。你從這四個條件逐一去對照代碼定位問題就快很多。我當(dāng)時在試卷上直接把這四條列在草稿紙上然后逐個打鉤排除效率很高。3. 計算機網(wǎng)絡(luò)與Linux考點紙上談兵不如真抓實測3.1 TCP三次握手與狀態(tài)遷移絕不能只背“三次”和“四次”網(wǎng)絡(luò)部分的題占了不少篇幅TCP協(xié)議是絕對核心。2015年考了三次握手、四次揮手、TIME_WAIT狀態(tài)、擁塞控制這些經(jīng)典考點。但是別以為把狀態(tài)圖背下來就萬事大吉題目的問法非常刁鉆。比如問主動關(guān)閉連接的一方在TIME_WAIT狀態(tài)需要等待多久為什么答案是2MSL大約是1到4分鐘取決于系統(tǒng)實現(xiàn)。為什么非要等2MSL因為要保證最后一個ACK能夠到達對端如果ACK丟失對端會重發(fā)FIN主動關(guān)閉方需要有時間來處理這個重發(fā)的FIN同時還要保證舊連接中的所有報文在網(wǎng)絡(luò)中徹底消失避免干擾新連接。這個知識點在基礎(chǔ)平臺的實際工作中非常重要。你開發(fā)一個高并發(fā)短連接服務(wù)連接頻繁建立和關(guān)閉如果服務(wù)器作為主動關(guān)閉方TIME_WAIT狀態(tài)的socket會大量堆積導(dǎo)致端口耗盡或者連接建立失敗。我自己做長連接網(wǎng)關(guān)時遇到過幾次這樣的線上問題最終方案都是調(diào)整tcp_tw_reuse和tcp_max_tw_buckets參數(shù)或者改造連接復(fù)用邏輯。筆試考TIME_WAIT本質(zhì)上就是在篩選有多少人真的寫過網(wǎng)絡(luò)服務(wù)而不只是看過《TCP/IP詳解》。還有一道關(guān)于TCP擁塞控制的題問了慢啟動和擁塞避免的區(qū)別。這里有個容易混淆的點慢啟動是每收到一個ACK擁塞窗口增加一個MSS所以是指數(shù)增長擁塞避免是每經(jīng)過一個RTT窗口加一是線性增長。很多人的錯誤在于把慢啟動理解為“每次增加一點點的緩慢過程”但實際上慢啟動名字叫slow增長卻非??臁:髞砦易约赫{(diào)網(wǎng)絡(luò)性能的時候才真正有了體感慢啟動在大帶寬高延遲的鏈路上可能要花很長時間才能把窗口漲到目標(biāo)值所以出現(xiàn)了TCP Fast Open、初始窗口擴大這些優(yōu)化手段。筆試考這個是想看你知不知道瓶頸在哪。3.2 select、poll、epoll基礎(chǔ)平臺的必考三兄弟2015年的試卷已經(jīng)考了I/O多路復(fù)用而且考得不淺。題目直接給了三種模型的對比表格讓你補充完整??嫉帽容^細(xì)的點包括select有FD_SETSIZE限制默認(rèn)1024poll沒有連接數(shù)限制但性能隨連接數(shù)線性下降epoll通過紅黑樹和就緒鏈表實現(xiàn)事件驅(qū)動在連接數(shù)巨大但活躍連接很少的場景下優(yōu)勢明顯。這里我想多說幾句關(guān)于邊緣觸發(fā)和水平觸發(fā)的區(qū)別因為這是實際開發(fā)中最容易出問題的地方。水平觸發(fā)是只要緩沖區(qū)還有數(shù)據(jù)可讀就會一直通知你邊緣觸發(fā)是只有當(dāng)有新數(shù)據(jù)到達時才通知一次。邊緣觸發(fā)模式下你必須一次性把數(shù)據(jù)讀完否則就會丟數(shù)據(jù)。解決辦法是配合非阻塞IO循環(huán)讀取直到read返回EAGAIN。我記得當(dāng)時筆試題里給了一段epoll邊緣觸發(fā)的代碼片段讓你判斷為什么活躍連接處理完后還有大量socket未讀取。答案就是緩沖區(qū)數(shù)據(jù)在最后一次read之后還有剩余但因為沒有新數(shù)據(jù)到達邊緣觸發(fā)不再通知于是這些數(shù)據(jù)一直躺在內(nèi)核緩沖里。這種坑是真正寫代碼時才能發(fā)現(xiàn)的問題筆試考了其實是在幫你提前踩坑。3.3 Linux調(diào)試和性能命令筆試考得不深但工作中天天用Linux相關(guān)的題在筆試中占比不是最高但一旦出現(xiàn)就非常實用。2015年有一道題是給出一個進程PID問用什么命令查看這個進程監(jiān)聽的端口。答案是netstat -tlnp或者lsof -p PID | grep LISTEN。還有一道題是系統(tǒng)Load Average過高問排查步驟這就完全是個開放式問題了。我的答題套路是自頂向下先看負(fù)載情況uptime再看CPU和內(nèi)存top/free然后用vmstat看上下文切換和等待隊列再用iostat看磁盤IO最后用perf或者strace定位到具體進程和系統(tǒng)調(diào)用。這個排查順序不是拍腦袋定的而是一種從現(xiàn)象到原因逐步收斂的思路?,F(xiàn)在的筆試題越來越喜歡這種“場景題”因為這類問題的答案能直接反映候選人的實戰(zhàn)經(jīng)驗。如果你只是知道命令的名字不知道什么情況下用哪個命令回答起來會非常散亂。另外gdb的基礎(chǔ)使用在筆試中也出現(xiàn)過。比如查看core dump文件用什么命令、如何查看當(dāng)前線程的調(diào)用棧。核心答案是gdb ./program core進入后thread apply all bt打印所有線程的堆棧?;A(chǔ)平臺研發(fā)的人不可能不跟crash打交道core文件就是我們破案的關(guān)鍵線索。這個技能用熟了很多疑難雜癥都能快速定位。4. 數(shù)據(jù)結(jié)構(gòu)與算法解題思路比代碼本身更重要4.1 鏈表和二叉樹基本功考察的重災(zāi)區(qū)算法部分的題目老實說2015年不是特別難但勝在出題角度比較務(wù)實。鏈表反轉(zhuǎn)、判斷鏈表是否有環(huán)、二叉樹前中后序遍歷、最近公共祖先這些都是標(biāo)配。題目不難難點在于時間和空間復(fù)雜度有沒有達到最優(yōu)。我記得有一道鏈表題要求O(1)空間復(fù)雜度刪除單鏈表中的某個非尾節(jié)點。常規(guī)思路是找到前驅(qū)節(jié)點再刪除但這樣就不得不遍歷鏈表。標(biāo)準(zhǔn)解法是“偷梁換柱”——把當(dāng)前節(jié)點的值替換成下一個節(jié)點的值然后刪除下一個節(jié)點。這個解法雖然有點“作弊”的味道但完美契合了題目的約束。這類題目告訴你一個重要道理算法題先看限制條件再想數(shù)據(jù)結(jié)構(gòu)的特殊性質(zhì)。很多時候不是你想不到思路而是沒有把題目的約束讀透。二叉樹相關(guān)的題目中非遞歸遍歷是高頻考點因為它考察的不只是“會遞歸”而是你能不能手動模擬棧的過程。筆試時我建議對層序遍歷多上點心因為基礎(chǔ)平臺開發(fā)中序列化和反序列化二叉樹、按層輸出等場景都很常見。有一道題是給定二叉樹的前序遍歷和中序遍歷結(jié)果讓你重建二叉樹。這題背后是分治思想前序遍歷的第一個節(jié)點是根中序遍歷中根的位置把序列分成左右子樹然后遞歸。理解了分治思想代碼寫起來就順理成章。4.2 動態(tài)規(guī)劃和貪心筆試?yán)锏姆炙畮X動態(tài)規(guī)劃在2015年的筆試中也占了一席之地。我記得有一道最長公共子序列的題屬于經(jīng)典DP入門。難點在于你要能寫出狀態(tài)轉(zhuǎn)移方程并且能說出為什么dp[i][j]的定義是這樣。后來我面試實習(xí)生時經(jīng)常發(fā)現(xiàn)一個現(xiàn)象很多人能把代碼背下來但問為什么dp數(shù)組多開一行一列就說不清楚了。原因在于沒有真正理解“空串參與比較”這個設(shè)計。多開一行一列是為了處理邊界條件讓i或j為0時dp[i][j]直接等于0不用特判。還有一道編輯距離的題這個在面試中出現(xiàn)的頻率極高。編輯距離的狀態(tài)轉(zhuǎn)移方程是如果字符相同dp[i][j]dp[i-1][j-1]不同則取插入、刪除、替換三種操作的最小值加1。筆試時我并不需要寫出完整代碼關(guān)鍵是畫出DP表格的推導(dǎo)過程。但實際工作中文本相似度計算、拼寫糾錯、基因序列比對底層都是編輯距離算法。你把這個狀態(tài)轉(zhuǎn)移想明白了后來學(xué)習(xí)更復(fù)雜的最短編輯路徑、diff算法會輕松很多。貪心算法在筆試題里一般是和排序結(jié)合出現(xiàn)的。比如活動選擇問題按結(jié)束時間排序依次選擇下一個與當(dāng)前不沖突的活動。這類題目的陷阱在于想當(dāng)然——面試者容易在看到“全局最優(yōu)”時認(rèn)為貪心可行但很多題目因為缺少貪心選擇性質(zhì)正確答案是動態(tài)規(guī)劃。所以在答貪心題時至少要能簡單證明貪心策略的正確性哪怕只是一句話的直覺每一步選擇局部最優(yōu)且這個選擇不限制后續(xù)選擇那么最終就是全局最優(yōu)。4.3 海量數(shù)據(jù)處理實習(xí)生崗也敢考膽子不小2015年的試卷里有一道海量數(shù)據(jù)題給定一個很大很大的日志文件找出出現(xiàn)頻率最高的前100個IP。這在當(dāng)時還是很超前的考點因為海量數(shù)據(jù)處理一般是社招填空題的保留節(jié)目。不過這題放在基礎(chǔ)平臺研發(fā)的實習(xí)生筆試?yán)锊⒉贿`和畢竟那個崗位干的活就是處理海量數(shù)據(jù)。答題思路要分兩步第一步如果日志文件大到內(nèi)存裝不下需要哈希分片把大文件拆成多個可以裝進內(nèi)存的小文件然后分別統(tǒng)計每個小文件的top100第二步對每個小文件的top100做外部排序或堆排序合并得到全局top100。如果用哈希分片要注意同一個IP必須hash到同一個小文件中否則統(tǒng)計結(jié)果會不準(zhǔn)確。還有個細(xì)節(jié)是哈希函數(shù)的選擇要盡可能使數(shù)據(jù)分布均勻避免某個小文件仍然過大。這種題目現(xiàn)在的面試?yán)飵缀醭闪藰?biāo)配但2015年能考出來說明阿里的基礎(chǔ)平臺團隊對候選人的要求一直很高。我會建議準(zhǔn)備此類題目的同學(xué)重點吃透四個字分而治之。不論是用哈希分片還是字典樹統(tǒng)計本質(zhì)都是把大問題拆成可以獨立解決的小問題最后再合并結(jié)果。5. 分布式系統(tǒng)與開放性問題沒有標(biāo)準(zhǔn)答案但看得出工程深度5.1 從CAP理論到一致性問題基礎(chǔ)平臺的底層邏輯分布式系統(tǒng)的題目在2015年其實是加分項答得好壞直接決定你能不能進下一輪面試。CAP理論是起點一致性、可用性、分區(qū)容錯性三個最多滿足兩個。但光說出這個結(jié)論是不夠的好的答案要能解釋“為什么不能三者兼得”。核心在于網(wǎng)絡(luò)分區(qū)時如果你選擇保持一致性就必須拒絕部分請求這犧牲了可用性如果你選擇保持可用性多個分區(qū)各自服務(wù)可能產(chǎn)生數(shù)據(jù)沖突這犧牲了一致性。這里我建議舉一個實際的例子。一個分布式KV存儲比如類似于早期版本的Tair如果某臺機器宕機了副本和其他節(jié)點失去通信。這時候系統(tǒng)有兩個選擇一是繼續(xù)對外提供服務(wù)但數(shù)據(jù)可能是不一致的二是停止服務(wù)等網(wǎng)絡(luò)恢復(fù)再做同步。前者是AP后者是CP。沒有絕對的好與壞只看業(yè)務(wù)場景。筆試題里有一道問的是“在什么場景下選擇CP什么場景下選擇AP”我的回答是交易支付類選CP因為寧可暫時不可用也不能賬目出錯商品瀏覽類選AP因為展示稍微舊一點沒關(guān)系但頁面不能打不開。這種問題沒有標(biāo)準(zhǔn)答案但能看出你有沒有真實的設(shè)計思考。5.2 一致性哈希基礎(chǔ)平臺的經(jīng)典設(shè)計一致性哈希在2015年的題目里有專門的考察。題目是設(shè)計一個分布式緩存系統(tǒng)要求增加節(jié)點或刪除節(jié)點時盡可能少地影響已有數(shù)據(jù)映射。如果你只回答“對key取?!蹦腔揪透鎰e復(fù)試了因為取模在節(jié)點變化時會導(dǎo)致絕大多數(shù)key重新映射造成緩存雪崩。一致性哈希的思路是把哈希值空間組織成一個虛擬的環(huán)每個節(jié)點映射到環(huán)上數(shù)據(jù)項也通過哈希映射到環(huán)上順時針找到的第一個節(jié)點就是存儲目標(biāo)。當(dāng)節(jié)點變化時只有該節(jié)點到前一個節(jié)點之間的數(shù)據(jù)需要遷移。但簡單的一致性哈希有一個問題節(jié)點數(shù)量少時哈希環(huán)上的節(jié)點分布可能非常不均勻。解決辦法是引入虛擬節(jié)點把每個物理節(jié)點復(fù)制成幾百個虛擬節(jié)點打散到環(huán)上。我在實際生產(chǎn)環(huán)境里手動實現(xiàn)過一致性哈希虛擬節(jié)點數(shù)取150到200時效果比較好。筆試中你如果能畫出環(huán)的示意圖再解釋虛擬節(jié)點的作用這道題基本就拿下了。5.3 開放設(shè)計題與軟技能考核除了技術(shù)知識點2015年的試卷還包含一些開放性的設(shè)計題。比如讓你設(shè)計一個短網(wǎng)址服務(wù)或者讓你解釋“如何保證消息只被消費一次”。這些題表面上沒有標(biāo)準(zhǔn)答案但考察的核心是兩方面需求澄清能力和邊界把控能力。以短網(wǎng)址服務(wù)為例如果你一上來就擺出Redis方案和MySQL方案說明你缺少第二步——為什么不先問清楚QPS是多少、數(shù)據(jù)量多大、需不需要自定義別名、過期時間是一年還是永久。大廠的筆試開放性題目除非你完全接觸過該類系統(tǒng)否則很可能答偏。我的建議是答題前先把關(guān)鍵問題列出來即使你沒有機會得到回答也要在答案中主動寫出“這里我假設(shè)系統(tǒng)的QPS是xxx量級在這個假設(shè)下我的方案是……”。這種帶著假設(shè)和前提的方案陳述方式本身就是工程思維的一部分。還有一類關(guān)于“技術(shù)選型”的題目比如讓你對比Redis和MySQL的使用場景。答題時要避免籠統(tǒng)地說“Redis快所以用它MySQL穩(wěn)定所以用它”而是要從數(shù)據(jù)模型、訪問模式、持久化要求、一致性要求四個維度拆開來看。把比較維度列清楚本身就證明你做過技術(shù)選型的功課。6. 備考建議和答題策略一份踩過坑之后整理的實戰(zhàn)清單6.1 時間投入與知識優(yōu)先級如果現(xiàn)在有同學(xué)要準(zhǔn)備類似的筆試我給你一個比較實用的時間分配建議。操作系統(tǒng)、網(wǎng)絡(luò)、C/C這幾塊占據(jù)六成以上的時間分布式和數(shù)據(jù)結(jié)構(gòu)的進階題占三成剩下的時間用來了解最新的技術(shù)動態(tài)。這不是拍腦袋定的比例而是我統(tǒng)計了這些年校招筆試題型的分布得出的結(jié)論?;A(chǔ)平臺研發(fā)崗尤其如此——你再怎么刷LeetCode如果fork的語義理解不透徹TCP揮手狀態(tài)圖畫不出來那些算法題拿到的分?jǐn)?shù)也補不上基礎(chǔ)題的窟窿。具體來說操作系統(tǒng)要重點掌握進程線程模型、上下文切換的代價、虛擬內(nèi)存與物理內(nèi)存的映射、用戶態(tài)與內(nèi)核態(tài)的切換條件、鎖的實現(xiàn)原理自旋鎖、互斥鎖、讀寫鎖。網(wǎng)絡(luò)方面要重點掌握TCP狀態(tài)機尤其是TIME_WAIT和CLOSE_WAIT、TCP擁塞控制的數(shù)據(jù)包行為、UDP與TCP選型權(quán)衡、HTTP/HTTPS的握手流程。C/C方面除了語法本身記得關(guān)注內(nèi)存布局、編譯器優(yōu)化對代碼行為的影響、RAII與智能指針的實現(xiàn)原理。這些知識點橫向覆蓋了筆試70%以上的出題范圍。6.2 答題節(jié)奏與失分陷阱2015年那次筆試我最大的教訓(xùn)是一道題卡太久了。那道題是一個復(fù)雜的狀態(tài)機分析題我花了將近二十分鐘去推演結(jié)果后面幾道本來可以輕松拿分的網(wǎng)絡(luò)題沒時間答仔細(xì)。后來總結(jié)出的答題順序是第一遍快速掃完全卷把有把握的題先做掉標(biāo)記出不確定的題最后再回頭啃硬骨頭。這個方法聽起來很老套但真的很管用因為基礎(chǔ)平臺筆試題量通常偏大時間就是分。失分陷阱主要集中在幾個地方運算符優(yōu)先級寫錯、忽略int溢出、多線程共享變量未加鎖、TCP狀態(tài)遷移沒考慮超時重傳、動態(tài)規(guī)劃的狀態(tài)定義不合理。筆試的客觀題往往是“看起來都會對答案錯一半”。我建議刷題時準(zhǔn)備一個錯題本但不要只記錄正確答案要把自己當(dāng)時錯誤的思考路徑寫下來。比如我當(dāng)年經(jīng)常把“進程上下文切換”和“線程上下文切換”的開銷差異搞混后來我在錯題本上寫了一句話線程切換雖然不切換地址空間但cache和TLB依然可能失效所以并不是“零開銷”。這么一寫記憶就深刻很多。6.3 從筆試到面試如何把試卷上的內(nèi)容變成面試素材筆試結(jié)束不等于復(fù)習(xí)結(jié)束很多筆試題目其實會在面試中被追問得更深。比如筆試題考了epoll的兩種觸發(fā)模式面試官可能會追問你在實際項目中用過epoll嗎當(dāng)時怎么處理邊緣觸發(fā)下的數(shù)據(jù)半包問題所以筆試后千萬不要對完答案就扔一邊而是要把每一道不確定的題變成一個學(xué)習(xí)入口順著知識點一路擴展下去。我自己的做法是給每道題做一個“一句話總結(jié)”。比如“LRU可以用雙向鏈表加哈希表實現(xiàn)關(guān)鍵是get和put的時間復(fù)雜度都是O(1)”再比如“TIME_WAIT不是bug是TCP可靠關(guān)閉的必要代價但可以通過連接復(fù)用和調(diào)參緩解”。這些一句話總結(jié)后來都成了我面試時的口頭表達素材。面試官通常會喜歡這種簡潔有力的概括因為它說明你真的理解了而不是背了很長的PPT。另外如果有條件的話筆試之后可以找一個同樣準(zhǔn)備面試的同學(xué)互相提問。兩個人輪流講一個知識點講的時候要注意能不能讓對方聽懂。如果對方聽完之后能用自己的話復(fù)述出來說明你講清楚了如果對方滿臉疑惑你需要回去再看看。把復(fù)雜的東西講簡單是基礎(chǔ)平臺研發(fā)工程師非常重要的能力因為這類崗位經(jīng)常需要寫技術(shù)方案、做code review、向團隊解釋系統(tǒng)設(shè)計表達本身就是工作的一部分。最后說幾句實在的2015年那場筆試過去很多年了但每次回頭看都會發(fā)現(xiàn)基礎(chǔ)平臺研發(fā)崗考察的核心一直沒有變操作系統(tǒng)、網(wǎng)絡(luò)、語言底層、算法與數(shù)據(jù)結(jié)構(gòu)、系統(tǒng)設(shè)計思維。技術(shù)棧會更新框架會替換但底層原理的穩(wěn)定性驚人地高?,F(xiàn)在網(wǎng)上能找到的面試題資源比當(dāng)年豐富太多但我反而覺得信息過載容易讓人陷入刷題的舒適區(qū)忘了回到根本。我個人最推薦的一種準(zhǔn)備方式是自己動手寫幾個小項目來驗證知識點而不是只看書和刷題。比如要實現(xiàn)一個簡單的線程池你自然會去思考任務(wù)隊列怎么加鎖、線程數(shù)量怎么定、空閑線程怎么回收要實現(xiàn)一個epoll高并發(fā)回聲服務(wù)器你自然會去理解水平觸發(fā)和邊緣觸發(fā)的差別要實現(xiàn)一個LRU緩存你自然會去設(shè)計哈希表和雙向鏈表的聯(lián)動。這些項目不需要多大但“親手做過”和“看過答案”之間的差距在筆試和面試中會體現(xiàn)得非常明顯?;A(chǔ)平臺研發(fā)這份工作終究是一個比拼內(nèi)功的方向內(nèi)功到位的人遲早會跑出來。