張小方|高性能服務器開發

我去年 12 月份從上一家公司離職,一直到今年 3 月份,基本上都在面試中度過來的。

先交代下背景:座標上海,做技術開發,我本人求職的職位是linux服務器開發,最傾向的職位是服務器開發主程或技術經理。我本人也是上幾家公司的面試官,因爲接下來幾年面臨着成家養小孩,技術上也到了瓶頸期,雖然拿了不少offer,但是想綜合比對一下再做決定。於是投遞了很多家公司。我先後去了如下一些公司:騰訊、百度、阿里的螞蟻金服和國際支付寶部門(兩個部門,兩次面試)、餓了麼、愛奇藝、360、攜程網、京東、華爲、bilibili、上海黃金交易所、東方財富網、zilliz、掌門集團(做無線萬能鑰匙的那一家)、喜馬拉雅聽書、UCLOUD、峯果網絡、華爾街見聞、萬得財經、匯正財經、逗屋網絡、朝陽永續,還有數家小規模的公司或創業公司吧。

爲了避免引起不必要的糾紛,下面我就不說具體的公司名稱了。技術面試的細節我儘量寫的詳細一點,希望對大家有參考價值,技術面試大致有三種情形:

第一類

以百度、愛奇藝等爲代表的,以數據結構和算法爲主,首先是簡單地瞭解下你之前的工作經歷和項目經驗,然後就是算法和數據結構題目,具體涉及到以下內容:

1. 快速排序(包括算法步驟、平均算法複雜度、最好和最壞的情形),有人說校招要把算法寫出來,我是社招,所以描述一下算法過程即可。

2. 寫二分查找算法,這個儘管是社招,但是一般也不難,所以要求面試者寫出來。但是很多公司,比如不會直接讓你寫算法,而是結合一個具體場景來提問,然後讓你自己聯想到二分查找,比如求一個數的平方根。

3. 鏈表,常見的面試題有寫一個鏈表中刪除一個節點的算法、單鏈表倒轉、兩個鏈表找相交的部分,這個一般必須得完全無誤的情況下寫出來;

4. 自己實現一些基礎的函數,例如strcpy / memcpy / memmov / atoi,同樣的道理,這些必須完全無誤且高效地寫出來,比如你的實現中有動態分配堆內存,那麼這道題目就算答錯。

第3點和第4點的關鍵點一般在於考察你的代碼風格、對邊界條件的處理,比如判斷指針是否爲空,千萬不要故意不考慮這種情形,即使你知道也不行,只要你不寫,一般面試官就認爲你的思路不周詳,容錯率低;再比如,單鏈表的倒轉,最後的返回值肯定是倒轉後的鏈表頭結點,這樣才能引用一個鏈表,這些都是面試官想考慮的重點。

5. 哈希表,對哈希表的細節要求很高,比如哈希表的衝突檢測、哈希函數常用實現、算法複雜度;比如百度二面就讓我寫一個哈希表插入元素算法,元素類型是任意類型。

6. AVL樹和B樹的概念、細節,比如會問 mysql 數據庫的索引的實現原理,基本上就等於問你 B 樹了。

7. 紅黑樹,這個基本上必問的一個數據結構,包括紅黑樹的概念、平均算法複雜度、最好最壞情況下的算法複雜度、、左右旋轉、顏色變換。面試官常見的算法套路有:你熟悉 C++ 的 stl 嗎?你說熟悉,ok,stl 的 map 用過吧?用過,ok,那map是如何實現的?紅黑樹,ok,那什麼是紅黑樹?這樣提問,紅黑樹就開始了。Java的也類似。

第二類

以餓了麼、bilibli、喜馬拉雅、360、攜程等爲代表的,兼顧算法數據結構和其他開發技術,算法和數據結構部分上文提過了,下面提一下其他技術,大致包括以下東西:

1. 以C++語言爲例

(不是 C++ 開發的朋友可以跳過這一點),第一類是基礎的 C++ 問題,常見的有 C++ 的繼承體系中 virtual 關鍵字的作用(如繼承關係中析構函數爲什麼要申明成 virtual 函數,如果不申明爲 virtual 會有什麼影響)、

在涉及到父子類時構造與析構函數的執行順序、多重繼承時類的成員列表在地址空間的排列;static 關鍵字的作用,static_cast / reinterpret_cast / dynamic_cast 等幾個轉換符的使用場景;問的最多的就是虛表的佈局,尤其是菱形繼承(B 和 C 繼承 A,D 繼承 B 和 C)時每個對象的空間結構分佈,比如問 D 有幾份虛表,D 中 B 和 C 的成員空間排布。

另外,如果你應聘的職位使用 C++ 開發,很多公司會問你一些 C++ 11 的東西(或者問 boost 庫,基本上都一樣),這個你用過就用過,沒有用過就說沒用過不要裝 X,常見的 C++ 11 需要掌握的一些技術庫我也列舉一下吧(JAVA 及其他語言的讀者可以忽略):

1.auto 關鍵字;

2.for - each 循環;

3.右值及移動構造函數+ std::forward + std::move + stl容器新增的emplace_back()方法;

4.std::thread 庫、std::chrono 庫、std::bind/std::function 庫;

5.智能指針系列

(std::shared_ptr/std::

unique_ptr/std::weak_ptr)

(智能指針的實現原理一定要知道,最好是自己實現過)

6.線程庫std::thread+線程同步技術庫

std::mutex/std::condition_variable/std::lock_guard等;

7.lamda 表達式(JAVA 中現在也常常考察lamda表達式的作用);

其他的就是一些關鍵字的用法(override、final、delete),還有就是一些細節如可以像 JAVA 一樣在類成員變量定義處給出初始化值。

2. 網絡通信問題

比如協議棧的層級關係,三次握手和四次揮手的【細節】。

注意我說的是細節,比如 CLOSE_WAIT 和 TIME_WAIT 狀態(bilibili 問了這樣一個問題,你可以感受一下:A 與 B 建立了正常連接後,從未相互發過數據,這個時候 B 突然機器重啓,問 A 此時的 tcp 狀態處於什麼狀態?

如何消除服務器程序中的這個狀態?

萬得問過流量擁塞和控制機制、騰訊問過 tcp 和 ip 包頭常見有哪些字段),東方財富網問了阻塞和非阻塞 socket 在 send、recv 函數上的行爲表現,異步 connect 函數的寫法,select 函數的用法,epoll 與 select 的區別。

基本上只要問到 epoll,必問:

1.epoll 的水平模式和邊緣模式的區別;

一些 socket 選項的用法,nagle / 2.keepalive / linger 等選項的區別;

3.tcp / udp 的區別和適用場景;

4.通信協議如何設計避免粘包;

5.http 協議的 get 和 post 方法的區別(問的比較深的會讓你畫出 http 協議的格式。

【參照這篇文章中關於http協議格式的講解:】

http://blog.csdn.net/analogous_love/article/details/72540130);

windows 用戶可能會問到完成端口模型(IOCP),網絡通信方面的問題,我專門開了一個知乎live系統地總結了一下,有興趣的朋友可以看這裏:

https://www.zhihu.com/lives/922110858308485120

和這裏:

https://www.zhihu.com/lives/902113324999778304。

總之,網絡通信問題能搞的多清楚就可以搞的多清楚,最起碼把 tcp 應用層的各種 socket API 的用法細節搞清楚。

3. 操作系統原理性的東西

比如上海黃金交易所、喜馬拉雅聽書問了

linux 下 elf 文件的節結構,映射到進程地址空間後,分別對應哪些段,相關的問題還有,全局變量、靜態存儲在進程地址空間的哪裏;

堆和棧的區別,棧的結構,棧的細節一點要搞的特別清楚,因爲一些對技術要求比較高的公司會問的比較深入,例如京東的一面是讓我先寫一個從 1 加到 100 的求和函數,然後讓我寫出這個函數的彙編代碼(JAVA 開發的同學可能會讓你試着去寫一點 JVM 的指令),如果你對棧的結構(如函數參數入棧順序、函數局部變量在棧中的佈局、棧幀指針和棧頂指針位置)不熟悉的話,這題目就無法答對了;

棧的問題,可能會以常見的函數調用方式來提問,常見的函數調用有如下:

__cdecl/__stdcall/__thiscall/__fastcall的區別,比如像printf這樣具有不定參數的函數爲什麼不能使用__stdcall;

餓了麼二面問了:

操作系統的保護模式實模式,中斷向量表,linux 下的 CAS。

還有就是進程和線程的聯繫與區別,問的最多的就是線程之間的一些同步技術,如互斥體、信號量、條件變量等(Windows 上還有事件、臨界區等),這些東西你必須熟悉到具體的API函數使用的層面上來,從另外一個角度來說,這是咱們實際工作中編碼最常用的東西,如果你連這個都不能熟練使用,那麼你肯定不是一個合格的開發者。

這類問題還可以引申爲:

什麼是死鎖、如何避免死鎖;進程之間通信的常用技術也需要掌握,常用的通信方式(linux 下)有共享內存、匿名和具名管道、socket、消息隊列等等,管道和 socket 是兩個必須深入掌握的考察點(與上面網絡通信有點重複);

linux 系統下可能還會問什麼是 daemon 進程,如何產生 daemo 進程,什麼是殭屍進程,殭屍進程如何產生和消除(bilibili問過)。

4. 第四類就是一個使用過的開源技術

比如代表 nosql 技術的的 redis;網絡庫 libevent 等等;數據庫如 mysql 的一些東西。

這個一般不做硬性要求,但是這裏必須強調的就是 redis,熟練使用 redis 甚至研究過 redis 源碼,現在一般是對做後臺開發的技術硬性要求或者說不可缺少的部分,基於 redis 的面試題既可以聊算法與數據結構,也可以聊網絡框架等等一類東西。

我面試的公司中基本上百分之九十以上都問到了 redis,只是深淺不一而已,比如喜馬拉雅問了 redis 的數據存儲結構、rehash;bilibili 問了 redis 的事務與集羣。

關於 JAVA 的,阿里的螞蟻金服問了如下一些問題(我儘量列舉下我能想起來的):

java.lang.Object 有哪些常用的方法;

1.改寫一個類的 toString 方法需要注意哪些問題;

2.hashCode 方法如使用;

3.== 與 equals 的區別;

4.線程創建的幾種方法,各自的使用場景;

5.hashmap、hashtable 的數據結構實現;

6.java 線程同步有哪些方法、各自的優缺點;

7.jvm 的結構,java 代碼優化等等。

第三類

以百度、愛奇藝等爲代表的,以數據結構和算法爲主,首先是簡單地瞭解下你之前的工作經歷和項目經驗,然後就是算法和數據結構題目,具體涉及到以下內容:

比如遊戲公司會關心你是否有某某類型的遊戲開發經驗、股票類公司會關心你是否有過證券或者交易系統的開發經驗等。我的經驗就是這類公司,能去的話可以去,不能去的話就當積累面試經驗。

業務開發哪裏都能找到,真正的重視技術的公司,應該是廣大做技術尤其是初中級開發的朋友應該值得關心的事情。

第四類

不靠譜型公司,我遇到的大致有四類:

第一類:裝X忽悠型

面試過程冗長繁瑣,比如號稱每一百份簡歷中才發一個面試邀請,號稱每一個面試者發一個 offer,號稱硅谷風格,我面試的有一家公司就是這個樣子,先是一輪長長的電話面試,然後是五輪技術面試,前三輪是刷 leetcode 上原題。

然後後幾輪面試,面試官從基本的操作系統的中斷、GDT、LDT、分表分頁機制問到上層高併發海量數據的架構,說的不好聽,真是從外太空聊到內子宮,最後問具體職位做什麼時,要麼遮遮掩掩要麼原型畢露;或者討論薪資時,要麼面露難色要麼各種畫餅,但是實際就給不了多少薪水的。

第二類:佛性公司

面試下來,全程面試官面帶微笑,問你的問題你回答的面試官也很贊同,但最後你就沒通過,我猜測要麼公司不是很缺人,想觀望一下是否有合適的人才;要麼招聘信息上開的薪資給不到。

第三類:老奶奶裹腳布型公司

其特點是面試週期長,往往第一輪面試通知你過了,讓你回去等上十天半個月後,給你打電話通知你來第二輪面試,面試要求穿正裝,帶好各種證件,面試前必須先查驗你的身份證、學歷證學位證,甚至是四六級考試證等等,麻煩至極,即使你一路過關斬將過了終面,薪資也給不了多少。

大家都是要養家餬口的,都是忙着找工作,誰有時間和你耗上十天半個月呢?

第四類:不尊重人類型公司

我這裏說的不尊重人,不是指的是面試過程中對你人身攻擊,而是不根據你的工作年限和經驗隨意安排面試官,舉個例子,比如你工作十年,你去面試一個技術總監的職位,對方公司安排一個工作不滿兩年的部門職員作爲面試官,這個面試官如果是走過場可以理解,但是非要和你糾結一個如二進制位移、現代編譯器要不要在子類析構函數前加 virtual 關鍵字這些技術細節就沒必要了。

還有一類就是故意問一些刁鑽的問題,或者全場都心不在焉、玩手機、漫不經心的面試官,比如問你 tcp 協議頭有多少個字段,每個字段是幹啥的。

遇到這一類面試官我的經驗就是要麼婉拒,要麼直接懟回去。

下面再說下面試中需要注意的一些細節:

第一,如果你的工作年限不長,尤其是渴望在技術方面有一定的造詣,那麼你首先考慮的應該是新的單位是否能有利於你技術上的成長,而不是兩份同樣的工作,薪資上的上下相差的三五千、五六千。如果想轉行的同學(比如從客戶端轉服務器,從 C++ 轉 JAVA),不要因爲薪資突然變低而拒絕這種陣痛,要把目光放長遠一點。

第二,一些公司雖然招聘信息上寫了最多能給到多少多少,但實際即使你全程面試下來都很完美,可能最終你也會因爲薪資要求達不到不被錄取。

第三,一些根本不想去的公司,如果你有時間的話,去面試積累下經驗也不是什麼壞事。

第四,面試的時候,同時也是你在考察面試官,一般面試官問你的問題,你能回答出來的在百分之八十左右,這樣的公司可以考慮去入職,你進去的話可能纔會在技術上有一些提升。

如果你全場秒殺面試官的題目,你的技術天花板可能也在那裏。

第五,面試的時候聊清楚你將來的職位內容,避免進去客串一些不想做的工作。

第六,遇到不會的面試題,不要直接就否定自己,可以嘗試着去和麪試官溝通一下,或者要求給點提示或者思路。

第七,不要輕視筆試中的一些數學智力題目,認真作答,試問算法不也是數學智力題嗎?

第八,自信一點,每個人的經歷和經驗都是獨一無二的,面試的時候,一些特定領域的問題,回答不出來也不要太在意。

相關文章