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