2020螞蟻金服、頭條、拼多多的面試總結(純乾貨獻上) 準備過程 螞蟻金服 拼多多 字節跳動 這些年看過的書:

文章有點長,請耐心看完,絕對有收穫!不想聽我BB直接進入面試分享:

  • 準備過程
  • 螞蟻金服面試分享
  • 拼多多面試分享
  • 字節跳動面試分享
  • 總結

說起來開始進行面試是年前倒數第二週,上午9點,我還在去公司的公交上,突然收到螞蟻的面試電話,其實算不上真正的面試。面試官只是和我聊了下他們在做的事情(主要是做雙十一這裏大促的穩定性保障,偏中間件吧),說的很詳細,然後和我溝通了下是否有興趣,我表示有興趣,後面就收到正式面試的通知,最後沒選擇去螞蟻表示抱歉。

當時我自己也準備出去看看機會,順便看看自己的實力。當時我其實挺糾結的,一方面現在部門也正需要我,還是可以有一番作爲的,另一方面覺得近一年來進步緩慢,沒有以前飛速進步的成就感了,而且業務和技術偏於穩定,加上自己也屬於那種比較懶散的人,骨子裏還是希望能夠突破現狀,持續在技術上有所精進。

在開始正式的總結之前,還是希望各位同仁能否聽我繼續發泄一會,抱拳!

我翻開自己2018年初立的flag,覺得甚是慚愧。其中就有一條是保持一週寫一篇博客,奈何中間因爲各種原因沒能堅持下去。細細想來,主要是自己沒能真正靜下來心認真投入到技術的研究和學習,那麼爲什麼會這樣?說白了還是因爲沒有確定目標或者目標不明確,沒有目標或者目標不明確都可能導致行動的失敗。

那麼問題來了,目標是啥?就我而言,短期目標是深入研究某一項技術,比如最近在研究mysql,那麼深入研究一定要動手實踐並且有所產出,這就夠了麼?還需要我們能夠舉一反三,結合實際開發場景想一想日常開發要注意什麼,這中間有沒有什麼坑?可以看出,要進步真的不是一件簡單的事,這種反人類的行爲需要我們克服自我的弱點,逐漸形成習慣。真正牛逼的人,從不覺得認真學習是一件多麼難的事,因爲這已經形成了他的習慣,就和早上起牀刷牙洗臉那麼自然簡單。

扯了那麼多,開始進入正題,先後進行了螞蟻、拼多多和字節跳動的面試。

準備過程

先說說我自己的情況,我2016先在螞蟻實習了將近三個月,然後去了我現在的老東家,2.5年工作經驗,可以說畢業後就一直老老實實在老東家打怪升級,雖說有螞蟻的實習經歷,但是因爲時間太短,還是有點虛的。所以面試官看到我簡歷第一個問題絕對是這樣的。

“哇,你在螞蟻待過,不錯啊”,面試官笑嘻嘻地問到。“是的,還好”,我說。“爲啥才三個月?”,面試官臉色一沉問到。“嘩啦啦解釋一通。。。”,我解釋道。“哦,原來如此,那我們開始面試吧”,面試官一本正經說到。

尼瑪,早知道不寫螞蟻的實習經歷了,後面仔細一想,當初寫上螞蟻不就給簡歷加點料嘛。

言歸正傳,準備過程其實很早開始了(當然這不是說我工作時老想着跳槽,因爲我明白現在的老東家並不是終點,我還需要不斷提升),具體可追溯到從螞蟻離職的時候,當時出來也面了很多公司,沒啥大公司,面了大概5家公司,都拿到offer了。

工作之餘常常會去額外研究自己感興趣的技術以及工作用到的技術,力求把原理搞明白,並且會自己實踐一把。此外,買了N多書,基本有時間就會去看,補補基礎,什麼操作系統、數據結構與算法、MySQL、JDK之類的源碼,基本都好好溫習了(文末會列一下自己看過的書和一些好的資料)。我深知基礎就像“木桶效應”的短板,決定了能裝多少水。

此外,在正式決定看機會之前,我給自己列了一個提綱,主要包括Java要掌握的核心要點,有不懂的就查資料搞懂。我給自己定位還是Java工程師,所以Java體系是一定要做到心中有數的,很多東西沒有常年的積累面試的時候很容易露餡,學習要對得起自己,不要騙人。

剩下的就是找平臺和內推了,除了螞蟻,頭條和拼多多都是找人內推的,感謝螞蟻面試官對我的欣賞,以後說不定會去螞蟻咯。

平臺:脈脈、GitHub、v2

螞蟻金服

一面

一面就做了一道算法題,要求兩小時內完成,給了長度爲N的有重複元素的數組,要求輸出第10大的數。典型的TopK問題,快排算法搞定。

算法題要注意的是合法性校驗、邊界條件以及異常的處理。另外,如果要寫測試用例,一定要保證測試覆蓋場景儘可能全。加上平時刷刷算法題,這種考覈應該沒問題的。

二面

  1. 自我介紹下唄
  2. 開源項目貢獻過代碼麼?(Dubbo提過一個打印accesslog的bug算麼)
  3. 目前在部門做什麼,業務簡單介紹下,內部有哪些系統,作用和交互過程說下
  4. Dubbo踩過哪些坑,分別是怎麼解決的?(說了異常處理時業務異常捕獲的問題,自定義了一個異常攔截器)
  5. 開始進入正題,說下你對線程安全的理解(多線程訪問同一個對象,如果不需要考慮額外的同步,調用對象的行爲就可以獲得正確的結果就是線程安全)
  6. 事務有哪些特性?(ACID)
  7. 怎麼理解原子性?(同一個事務下,多個操作要麼成功要麼失敗,不存在部分成功或者部分失敗的情況)
  8. 樂觀鎖和悲觀鎖的區別?(悲觀鎖假定會發生衝突,訪問的時候都要先獲得鎖,保證同一個時刻只有線程獲得鎖,讀讀也會阻塞;樂觀鎖假設不會發生衝突,只有在提交操作的時候檢查是否有衝突)這兩種鎖在Java和MySQL分別是怎麼實現的?(Java樂觀鎖通過CAS實現,悲觀鎖通過synchronize實現。mysql樂觀鎖通過MVCC,也就是版本實現,悲觀鎖可以通過select... for update加上排它鎖)
  9. HashMap爲什麼不是線程安全的?(多線程操作無併發控制,順便說了在擴容的時候多線程訪問時會造成死鎖,會形成一個環,不過擴容時多線程操作形成環的問題再JDK1.8已經解決,但多線程下使用HashMap還會有一些其他問題比如數據丟失,所以多線程下不應該使用HashMap,而應該使用ConcurrentHashMap)怎麼讓HashMap變得線程安全?(Collections的synchronize方法包裝一個線程安全的Map,或者直接用ConcurrentHashMap)兩者的區別是什麼?(前者直接在put和get方法加了synchronize同步,後者採用了分段鎖以及CAS支持更高的併發)
  10. jdk1.8對ConcurrentHashMap做了哪些優化?(插入的時候如果數組元素使用了紅黑樹,取消了分段鎖設計,synchronize替代了Lock鎖)爲什麼這樣優化?(避免衝突嚴重時鏈表多長,提高查詢效率,時間複雜度從O(N)提高到O(logN))
  11. redis主從機制瞭解麼?怎麼實現的?
  12. 有過GC調優的經歷麼?(有點虛,答得不是很好)
  13. 有什麼想問的麼?

三面

  1. 簡單自我介紹下
  2. 監控系統怎麼做的,分爲哪些模塊,模塊之間怎麼交互的?用的什麼數據庫?(MySQL)使用什麼存儲引擎,爲什麼使用InnnoDB?(支持事務、聚簇索引、MVCC)
  3. 訂單表有做拆分麼,怎麼拆的?(垂直拆分和水平拆分)
  4. 水平拆分後查詢過程描述下
  5. 如果落到某個分片的數據很大怎麼辦?(按照某種規則,比如哈希取模、range,將單張表拆分爲多張表)
  6. 哈希取模會有什麼問題麼?(有的,數據分佈不均,擴容縮容相對複雜 )
  7. 分庫分表後怎麼解決讀寫壓力?(一主多從、多主多從)
  8. 拆分後主鍵怎麼保證惟一?(UUID、Snowflake算法)
  9. Snowflake生成的ID是全局遞增唯一麼?(不是,只是全局唯一,單機遞增)
  10. 怎麼實現全局遞增的唯一ID?(講了TDDL的一次取一批ID,然後再本地慢慢分配的做法)
  11. Mysql的索引結構說下(說了B+樹,B+樹可以對葉子結點順序查找,因爲葉子結點存放了數據結點且有序)
  12. 主鍵索引和普通索引的區別(主鍵索引的葉子結點存放了整行記錄,普通索引的葉子結點存放了主鍵ID,查詢的時候需要做一次回表查詢)一定要回表查詢麼?(不一定,當查詢的字段剛好是索引的字段或者索引的一部分,就可以不用回表,這也是索引覆蓋的原理)
  13. 你們系統目前的瓶頸在哪裏?
  14. 你打算怎麼優化?簡要說下你的優化思路
  15. 有什麼想問我麼?

四面

  1. 介紹下自己
  2. 爲什麼要做逆向?
  3. 怎麼理解微服務?
  4. 服務治理怎麼實現的?(說了限流、壓測、監控等模塊的實現)
  5. 這個不是中間件做的事麼,爲什麼你們部門做?(當時沒有單獨的中間件團隊,微服務剛搞不久,需要進行監控和性能優化)
  6. 說說Spring的生命週期吧
  7. 說說GC的過程(說了young gc和full gc的觸發條件和回收過程以及對象創建的過程)
  8. CMS GC有什麼問題?(併發清除算法,浮動垃圾,短暫停頓)
  9. 怎麼避免產生浮動垃圾?(記得有個VM參數設置可以讓掃描新生代之前進行一次young gc,但是因爲gc是虛擬機自動調度的,所以不保證一定執行。但是還有參數可以讓虛擬機強制執行一次young gc)
  10. 強制young gc會有什麼問題?(STW停頓時間變長)
  11. 知道G1麼?(瞭解一點 )
  12. 回收過程是怎麼樣的?(young gc、併發階段、混合階段、full gc,說了Remember Set)
  13. 你提到的Remember Set底層是怎麼實現的?
  14. 有什麼想問的麼?

五面

五面是HRBP面的,和我提前預約了時間,主要聊了之前在螞蟻的實習經歷、部門在做的事情、職業發展、福利待遇等。阿里面試官確實是具有一票否決權的,很看重你的價值觀是否match,一般都比較喜歡皮實的候選人。HR面一定要誠實,不要說謊,只要你說謊HR都會去證實,直接cut了。

  1. 之前螞蟻實習三個月怎麼不留下來?
  2. 實習的時候主管是誰?
  3. 實習做了哪些事情?(尼瑪這種也問?)
  4. 你對技術怎麼看?平時使用什麼技術棧?(阿里HR真的是既當爹又當媽,)
  5. 最近有在研究什麼東西麼
  6. 你對SRE怎麼看
  7. 對待遇有什麼預期麼

最後HR還對我說目前穩定性保障部挺缺人的,希望我儘快回覆。

小結

螞蟻面試比較重視基礎,所以Java那些基本功一定要紮實。螞蟻的工作環境還是挺讚的,因爲我面的是穩定性保障部門,還有許多單獨的小組,什麼三年1班,很有青春的感覺。面試官基本水平都比較高,基本都P7以上,除了基礎還問了不少架構設計方面的問題,收穫還是挺大的。

拼多多

面試前

面完螞蟻后,早就聽聞拼多多這個獨角獸,決定也去面一把。首先我在脈脈找了一個拼多多的HR,加了微信聊了下,發了簡歷便開始我的拼多多面試之旅。這裏要非常感謝拼多多HR小姐姐,從面試內推到offer確認一直都在幫我,人真的很nice。

一面

  1. 爲啥螞蟻只待了三個月?沒轉正?(轉正了,解釋了一通。。。)
  2. Java中的HashMap、TreeMap解釋下?(TreeMap紅黑樹,有序,HashMap無序,數組+鏈表)
  3. TreeMap查詢寫入的時間複雜度多少?(O(logN))
  4. HashMap多線程有什麼問題?(線程安全,死鎖)怎麼解決?( jdk1.8用了synchronize + CAS,擴容的時候通過CAS檢查是否有修改,是則重試)重試會有什麼問題麼?(CAS(Compare And Swap)是比較和交換,不會導致線程阻塞,但是因爲重試是通過自旋實現的,所以仍然會佔用CPU時間,還有ABA的問題)怎麼解決?(超時,限定自旋的次數,ABA可以通過原理變量AtomicStampedReference解決,原理利用版本號進行比較)超過重試次數如果仍然失敗怎麼辦?(synchronize互斥鎖)
  5. CAS和synchronize有什麼區別?都用synchronize不行麼?(CAS是樂觀鎖,不需要阻塞,硬件級別實現的原子性;synchronize會阻塞,JVM級別實現的原子性。使用場景不同,線程衝突嚴重時CAS會造成CPU壓力過大,導致吞吐量下降,synchronize的原理是先自旋然後阻塞,線程衝突嚴重仍然有較高的吞吐量,因爲線程都被阻塞了,不會佔用CPU )
  6. 如果要保證線程安全怎麼辦?(ConcurrentHashMap)
  7. ConcurrentHashMap怎麼實現線程安全的?(分段鎖)
  8. get需要加鎖麼,爲什麼?(不用,volatile關鍵字)
  9. volatile的作用是什麼?(保證內存可見性)
  10. 底層怎麼實現的?(說了主內存和工作內存,讀寫內存屏障,happen-before,並在紙上畫了線程交互圖)
  11. 在多核CPU下,可見性怎麼保證?(思考了一會,總線嗅探技術)
  12. 聊項目,系統之間是怎麼交互的?
  13. 系統併發多少,怎麼優化?
  14. 給我一張紙,畫了一個九方格,都填了數字,給一個MN矩陣,從1開始逆時針打印這MN個數,要求時間複雜度儘可能低(內心OS:之前貌似碰到過這題,最優解是怎麼實現來着)思考中。。。
  15. 可以先說下你的思路(想起來了,說了什麼時候要變換方向的條件,向右、向下、向左、向上,依此循環)
  16. 有什麼想問我的?

二面

  1. 自我介紹下
  2. 手上還有其他offer麼?(拿了螞蟻的offer)
  3. 部門組織結構是怎樣的?(這輪不是技術面麼,不過還是老老實實說了)
  4. 系統有哪些模塊,每個模塊用了哪些技術,數據怎麼流轉的?(面試官有點禿頂,一看級別就很高)給了我一張紙,我在上面簡單畫了下系統之間的流轉情況
  5. 鏈路追蹤的信息是怎麼傳遞的?(RpcContext的attachment,說了Span的結構:parentSpanId + curSpanId)
  6. SpanId怎麼保證唯一性?(UUID,說了下內部的定製改動)
  7. RpcContext是在什麼維度傳遞的?(線程)
  8. Dubbo的遠程調用怎麼實現的?(講了讀取配置、拼裝url、創建Invoker、服務導出、服務註冊以及消費者通過動態代理、filter、獲取Invoker列表、負載均衡等過程(嘩啦啦講了10多分鐘),我可以喝口水麼)
  9. Spring的單例是怎麼實現的?(單例註冊表)
  10. 爲什麼要單獨實現一個服務治理框架?(說了下內部剛搞微服務不久,主要對服務進行一些監控和性能優化)
  11. 誰主導的?內部還在使用麼?
  12. 逆向有想過怎麼做成通用麼?
  13. 有什麼想問的麼?

三面

二面老大面完後就直接HR面了,主要問了些職業發展、是否有其他offer、以及入職意向等問題,順便說了下公司的福利待遇等,都比較常規啦。不過要說的是手上有其他offer或者大廠經歷會有一定加分。

小結

拼多多的面試流程就簡單許多,畢竟是一個成立三年多的公司。面試難度中規中矩,只要基礎紮實應該不是問題。但不得不說工作強度很大,開始面試前HR就提前和我確認能否接受這樣強度的工作,想來的老鐵還是要做好準備

字節跳動

面試前

頭條的面試是三家裏最專業的,每次面試前有專門的HR和你約時間,確定OK後再進行面試。每次都是通過視頻面試,因爲都是之前都是電話面或現場面,所以視頻面試還是有點不自然。也有人覺得視頻面試體驗很贊,當然蘿蔔青菜各有所愛。最坑的二面的時候對方面試官的網絡老是掉線,最後很冤枉的掛了(當然有一些點答得不好也是原因之一)。所以還是有點遺憾的。

一面

  1. 先自我介紹下
  2. 聊項目,逆向系統是什麼意思
  3. 聊項目,逆向系統用了哪些技術
  4. 線程池的線程數怎麼確定?
  5. 如果是IO操作爲主怎麼確定?
  6. 如果計算型操作又怎麼確定?
  7. Redis熟悉麼,瞭解哪些數據結構?(說了zset) zset底層怎麼實現的?(跳錶)
  8. 跳錶的查詢過程是怎麼樣的,查詢和插入的時間複雜度?(說了先從第一層查找,不滿足就下沉到第二層找,因爲每一層都是有序的,寫入和插入的時間複雜度都是O(logN))
  9. 紅黑樹瞭解麼,時間複雜度?(說了是N叉平衡樹,O(logN))
  10. 既然兩個數據結構時間複雜度都是O(logN),zset爲什麼不用紅黑樹(跳錶實現簡單,踩坑成本低,紅黑樹每次插入都要通過旋轉以維持平衡,實現複雜)
  11. 點了點頭,說下Dubbo的原理?(說了服務註冊與發佈以及消費者調用的過程)踩過什麼坑沒有?(說了dubbo異常處理的和打印accesslog的問題)
  12. CAS瞭解麼?(說了CAS的實現)還了解其他同步機制麼?(說了synchronize以及兩者的區別,一個樂觀鎖,一個悲觀鎖)
  13. 那我們做一道題吧,數組A,2*n個元素,n個奇數、n個偶數,設計一個算法,使得數組奇數下標位置放置的都是奇數,偶數下標位置放置的都是偶數
  14. 先說下你的思路(從0下標開始遍歷,如果是奇數下標判斷該元素是否奇數,是則跳過,否則從該位置尋找下一個奇數)
  15. 下一個奇數?怎麼找?(有點懵逼,思考中。。)
  16. 有思路麼?(仍然是先遍歷一次數組,並對下標進行判斷,如果下標屬性和該位置元素不匹配從當前下標的下一個遍歷數組元素,然後替換)
  17. 你這樣時間複雜度有點高,如果要求O(N)要怎麼做(思考一會,答道“定義兩個指針,分別從下標0和1開始遍歷,遇見奇數位是是偶數和偶數位是奇數就停下,交換內容”)
  18. 時間差不多了,先到這吧。你有什麼想問我的?

二面

  1. 面試官和藹很多,你先介紹下自己吧
  2. 你對服務治理怎麼理解的?
  3. 項目中的限流怎麼實現的?(Guava ratelimiter,令牌桶算法)
  4. 具體怎麼實現的?(要點是固定速率且令牌數有限)
  5. 如果突然很多線程同時請求令牌,有什麼問題?(導致很多請求積壓,線程阻塞)
  6. 怎麼解決呢?(可以把積壓的請求放到消息隊列,然後異步處理)
  7. 如果不用消息隊列怎麼解決?(說了RateLimiter預消費的策略)
  8. 分佈式追蹤的上下文是怎麼存儲和傳遞的?(ThreadLocal + spanId,當前節點的spanId作爲下個節點的父spanId)
  9. Dubbo的RpcContext是怎麼傳遞的?(ThreadLocal)主線程的ThreadLocal怎麼傳遞到線程池?(說了先在主線程通過ThreadLocal的get方法拿到上下文信息,在線程池創建新的ThreadLocal並把之前獲取的上下文信息設置到ThreadLocal中。這裏要注意的線程池創建的ThreadLocal要在finally中手動remove,不然會有內存泄漏的問題)
  10. 你說的內存泄漏具體是怎麼產生的?(說了ThreadLocal的結構,主要分兩種場景:主線程仍然對ThreadLocal有引用和主線程不存在對ThreadLocal的引用。第一種場景因爲主線程仍然在運行,所以還是有對ThreadLocal的引用,那麼ThreadLocal變量的引用和value是不會被回收的。第二種場景雖然主線程不存在對ThreadLocal的引用,且該引用是弱引用,所以會在gc的時候被回收,但是對用的value不是弱引用,不會被內存回收,仍然會造成內存泄漏)
  11. 線程池的線程是不是必須手動remove纔可以回收value?(是的,因爲線程池的核心線程是一直存在的,如果不清理,那麼核心線程的threadLocals變量會一直持有ThreadLocal變量)
  12. 那你說的內存泄漏是指主線程還是線程池?(主線程 )
  13. 可是主線程不是都退出了,引用的對象不應該會主動回收麼?(面試官和內存泄漏槓上了),沉默了一會。。。
  14. 那你說下SpringMVC不同用戶登錄的信息怎麼保證線程安全的?(剛纔解釋的有點懵逼,一下沒反應過來,居然回答成鎖了。大腦有點暈了,此時已經一個小時過去了,感覺情況不妙。。。)
  15. 這個直接用ThreadLocal不就可以麼,你見過SpringMVC有鎖實現的代碼麼?(有點暈菜。。。)
  16. 我們聊聊mysql吧,說下索引結構(說了B+樹)
  17. 爲什麼使用B+樹?( 說了查詢效率高,O(logN),可以充分利用磁盤預讀的特性,多叉樹,深度小,葉子結點有序且存儲數據)
  18. 什麼是索引覆蓋?(忘記了。。。)
  19. Java爲什麼要設計雙親委派模型?
  20. 什麼時候需要自定義類加載器?
  21. 我們做一道題吧,手寫一個對象池
  22. 有什麼想問我的麼?(感覺我很多點都沒答好,是不是掛了(結果真的是) )

小結

頭條的面試確實很專業,每次面試官會提前給你發一個視頻鏈接,然後準點開始面試,而且考察的點都比較全。

面試官都有一個特點,會抓住一個值得深入的點或者你沒說清楚的點深入下去直到你把這個點講清楚,不然面試官會覺得你並沒有真正理解。二面面試官給了我一點建議,研究技術的時候一定要去研究產生的背景,弄明白在什麼場景解決什麼特定的問題,其實很多技術內部都是相通的。很誠懇,還是很感謝這位面試官大大。

總結

從年前開始面試到頭條面完大概一個多月的時間,真的有點身心俱疲的感覺。最後拿到了拼多多、螞蟻的offer,還是蠻幸運的。頭條的面試對我幫助很大,再次感謝面試官對我的誠懇建議,以及拼多多的HR對我的囉嗦的問題詳細解答。

這裏要說的是面試前要做好兩件事:簡歷和自我介紹,簡歷要好好回顧下自己做的一些項目,然後挑幾個亮點項目。自我介紹基本每輪面試都有,所以最好提前自己練習下,想好要講哪些東西,分別怎麼講。此外,簡歷提到的技術一定是自己深入研究過的,沒有深入研究也最好找點資料預熱下,不打無準備的仗。

這些年看過的書

《Effective Java》、《現代操作系統》、《TCP/IP詳解:卷一》、《代碼整潔之道》、《重構》、《Java程序性能優化》、《Spring實戰》、《Zookeeper》、《高性能MySQL》、《億級網站架構核心技術》、《可伸縮服務架構》、《Java編程思想》《微服務架構與實踐》 《Java併發編程實戰》《spring boot實戰》

說實話這些書很多隻看了一部分,我通常會帶着問題看書,不然看着看着就睡着了,簡直是催眠良藥。

****最後,附一張面試前準備資料**


有需要文中資料或其他Java架構資料和視頻解析, 可點此處獲取

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章