6月底離職了,在上家公司期間經(jīng)歷了各種各樣的線上故障,處置過各種各樣的問題,從剛開始的掉頭發(fā)到后面的游刃有余。這三年半對我職業(yè)生涯而言還是非常重要的一段,公司雖小,但也有了典型互聯(lián)網(wǎng)公司的技術(shù)架構(gòu),從而讓我有機(jī)會去面對各種各樣的技術(shù)問題。離職找工作,這里記錄下最近的一些面試。
字節(jié)-飛書組織架構(gòu)管理
這次面試是還未離職的時(shí)候,很多東西沒有好好的準(zhǔn)備,比如面試官問到的redis key的過期淘汰策略,redis的實(shí)現(xiàn)我整本書都看過,沒有準(zhǔn)備的情況下很多東西確實(shí)是忘了,還問到了go的GPM模型,當(dāng)然我的回答是不太了解,后面去看了下,跟tornado做了下對比,思想上是類似的,有epoll,有就緒隊(duì)列等等。問如何理解依賴倒置原則,有點(diǎn)懵,因?yàn)橐蕾嚨怪眠@個(gè)詞我早就忘了啥意思了,面試官提示了下就是依賴于抽象而不是具體的實(shí)現(xiàn),我看過設(shè)計(jì)模式、代碼大全,在生產(chǎn)中也寫過非常優(yōu)雅的代碼,用到過一些設(shè)計(jì)模式,對于抽象我認(rèn)為自己還是理解的比較深刻的,舉了個(gè)案例叭啦叭啦了一堆。
算法題都沒做,面完就估計(jì)自己應(yīng)該掛了,后面吸取了教訓(xùn),對于各種各樣的技術(shù)棧做了一次系統(tǒng)的回顧。
友情提示:阿里字節(jié)等有hr約的面試基本都有面試評價(jià)記錄,所以在沒有準(zhǔn)備的情況下不要貿(mào)然約面試,不然不好的面試評價(jià)可能會影響到篩簡歷。
智云健康-python技術(shù)專家
面試問到了flask的request,大概考的是線程隔離,我的回答是ThreadLocal,問我讓我自己如何實(shí)現(xiàn),我回答用dict,key是threadID,這樣可以隔離不同線程的數(shù)據(jù),python問的挺多的,其它的諸如數(shù)據(jù)庫、linux基本沒有問過。
總體面試的感覺比較草草了之,后面反饋一面未通過,原因是在工具和框架的深入度上以及Python高級語法和使用上有所欠缺,內(nèi)心os:這是我三年前的水平??!
帷幄-后端工程師
這次是到現(xiàn)場面的,公司盡可能讓候選人只跑一次,一上午走完整個(gè)流程,非常nice,HR也很親和。
技術(shù)面有兩輪,首先做了自我介紹,然后問我項(xiàng)目中各種各樣的點(diǎn)以及解決的一些問題,中間有一些波折,面試官對于項(xiàng)目的一些質(zhì)疑感覺未經(jīng)過大腦,其實(shí)項(xiàng)目中各種各樣的解決方案是基于當(dāng)時(shí)整體的技術(shù)業(yè)務(wù)架構(gòu)背景下的,并不是想象中那么簡單,算法題是兩個(gè)有序鏈表的合并,技術(shù)面和HR面都通過了,最終薪資未談妥。
長橋-后端工程師
本次面試主要考察的是go,問到了如何讓一個(gè)協(xié)程正常退出,我的第一反應(yīng)是代碼段執(zhí)行完了不就退出了么,沒有g(shù)et到面試官的點(diǎn),后面做了下功課,原來面試官要考察的是select,如果以自頂向下的思維來思考這個(gè)問題,select只是一部分,不是全部,如何保證一個(gè)協(xié)程能夠執(zhí)行完所有的代碼段并退出,那只要保證協(xié)程有退出的機(jī)制且不會被永遠(yuǎn)掛起,1是不能有死循環(huán),如果當(dāng)前協(xié)程有死循環(huán)那么就退出不了,如果其它協(xié)程有死循環(huán),那么非搶占式調(diào)度的單核cpu情況下,當(dāng)前協(xié)程不會有運(yùn)行的機(jī)會,2是不能有死鎖,如果兩個(gè)協(xié)程相互死鎖,就會被永遠(yuǎn)掛起,不會有任何執(zhí)行的機(jī)會,3是對于channel的讀寫需要有正常退出的機(jī)制,可以用select配合default、context或者超時(shí)的機(jī)制。這個(gè)問題我后面有和面試官探討,不過沒理我。問用到sync里面哪些東西,回答Metux、WaitGroup、Once,問還有其它的么,答沒有了,問到了字典是并發(fā)安全的么,有什么解決辦法,回答有用到過并發(fā)安全的字典,具體是哪個(gè)忘了(sync.Map)。問sync.Once的機(jī)制以及會不會重復(fù)執(zhí)行,我的回答是不會重復(fù)執(zhí)行,然后面試官說有的情況下會重復(fù)執(zhí)行,后面我查了一些資料,沒有發(fā)現(xiàn)有重復(fù)執(zhí)行的bug相關(guān)帖子,所以我的感覺是可能使用者寫的代碼有點(diǎn)問題,以我的經(jīng)歷來看,標(biāo)準(zhǔn)庫出問題的概率還是非常非常小的。問slice內(nèi)存分配的大小是多少,有點(diǎn)懵,當(dāng)時(shí)回答了擴(kuò)容機(jī)制,沒有了解內(nèi)存的大小,答案應(yīng)該說的是類型字節(jié)乘容量然后向上取整(優(yōu)化內(nèi)存碎片的機(jī)制),其它的諸如數(shù)據(jù)庫、linux、kv存儲沒有問到過。
本次面試一面未通過。
滴滴-后端工程師
上來問我做了哪些事情,我說主要工作是需求開發(fā),然后解決線上面臨的各種各樣的問題,還做過很多運(yùn)維相關(guān)的事情,面試官讓我介紹項(xiàng)目,叭啦叭啦介紹了很多,然后他來了一句所以整個(gè)項(xiàng)目中你就做了這點(diǎn)事情對吧(傲慢的語氣)?挺惱火的,很多東西都沒在簡歷里體現(xiàn)。問到了發(fā)紅包功能的細(xì)節(jié),支付是所有系統(tǒng)最軸心的功能了,從分布式事務(wù)的詞面意思來理解,本地扣除打款賬戶余額,然后調(diào)用第三方支付打款是一個(gè)典型的分布式事務(wù),需要解決的是中間狀態(tài)中可能出現(xiàn)的各種異常,狀態(tài)是最終一致性。最后編碼提是讓兩個(gè)go協(xié)程交替打印數(shù)組元素,稍微卡了下,最終實(shí)現(xiàn)了,但是可能跟他心中的標(biāo)準(zhǔn)答案有些差距吧。
結(jié)果是一面掛了,問hr哪里的問題好改進(jìn),答綜合過往背景和面試的結(jié)果和職位不太匹配,沒有具體說哪一方面。
圖菱視頻-后端工程師
一面有兩個(gè)面試官,問python有GIL,為什么還是并發(fā)不安全,答線程調(diào)度是操作系統(tǒng)級別且無序的,問裝飾器知道么有什么作用(太基礎(chǔ)了,我覺得如果招資深的可能這么面不合適),叭啦叭啦,問知道裝飾器的底層原理么,沒有g(shù)et到面試官的點(diǎn),我問面試官是否說語法糖的事情,我再仔細(xì)想了下,問到是否是指針指向裝飾器返回的函數(shù)(應(yīng)該是回答了他的問題),問go的slice擴(kuò)容的機(jī)制,這個(gè)比較簡單。問紅包打款模塊的細(xì)節(jié),叭啦叭啦,問為什么不能第三方打款成功之后再扣除本地賬戶的錢,這樣也能解決事務(wù)一致性的問題,有點(diǎn)懵,但是抽象出來就是A和B事務(wù)之間的順序性,紅包打款這里賬戶扣減是必要條件,不然會出現(xiàn)超發(fā)的問題,也就是B發(fā)生的前提條件是A。問有用到過設(shè)計(jì)模式么,我提到了python的logging模塊的handler設(shè)計(jì),這里雖然沒用到固定的某個(gè)模式,但是我覺的最重要的還是抽象本身。問mysql如果有兩個(gè)單獨(dú)的列索引a和b,查詢的語句是where a=xx and b=xx,mysql會用到哪個(gè)索引,答有可能用到有可能用不到(可能跟面試官的答案有點(diǎn)不一樣,頓了一下),還是自頂向下來思考這個(gè)問題,mysql的本身是為了高效的查詢,所以不管用不用到索引,用哪個(gè)索引都是為了達(dá)到高效的目的,一個(gè)查詢?nèi)绾螆?zhí)行是由cpu和io的代價(jià)來決定的(cost base),假定a和b列的區(qū)分度都非常低,那么掃全表的效率會更高(順序io),如果區(qū)分度都比較高,那么會傾向選擇區(qū)分度更高的索引(可以掃描更少的行),高效查詢是本質(zhì),掌握了本質(zhì)就不會在各種各樣的問題里迷失。算法題是二叉樹每層的和,層序遍歷的變種,很快寫完。
二面也是遠(yuǎn)程視頻,問有個(gè)接口返回n行數(shù)據(jù),數(shù)據(jù)從數(shù)據(jù)庫查,這個(gè)接口rt隨著n線性增長,比如請求10行消耗100ms,請求20行消耗200ms,猜可能是什么問題導(dǎo)致的,技術(shù)上的猜謎還是挺有意思的,我解決過的很多問題也是通過猜的形式來一步步推導(dǎo)出來的,這個(gè)面試題在現(xiàn)實(shí)中你首先得發(fā)現(xiàn)這個(gè)線性增長的規(guī)律才能一步步猜測推導(dǎo)(發(fā)現(xiàn)規(guī)律是第一步,很重要),答不太可能是因?yàn)椴?0行數(shù)據(jù)導(dǎo)致的,因?yàn)槿绻@些數(shù)據(jù)在磁盤上在一個(gè)頁內(nèi),那么讀10行還是讀20行都是一次IO,不會導(dǎo)致線性增長,那么有可能是在組裝最終的返回?cái)?shù)據(jù)里做了一些操作,導(dǎo)致rt增長,那么時(shí)間都花在哪去了,自頂向下思考,無非是cpu、網(wǎng)絡(luò)io等待、鎖等待等等,這里面最有可能的是網(wǎng)絡(luò)io操作,當(dāng)時(shí)我給的答案是可能遍歷列表的時(shí)候每次循環(huán)都請求了外部接口,面試官提示說是在django的項(xiàng)目里,假設(shè)沒有第三方接口調(diào)用,其實(shí)django我初期用過,現(xiàn)在不是很熟,面試完之后我想了下,也有可能是ORM內(nèi)的一些機(jī)制,在select完列表時(shí)又遍歷做了一遍關(guān)聯(lián)的查詢,本質(zhì)上還是io等待上,最終我說一個(gè)接口的完整的性能診斷還是要做apm,看看時(shí)間都花在哪去了,再做優(yōu)化。第二個(gè)是編碼優(yōu)化題,業(yè)務(wù)同學(xué)寫的代碼可能會爆棧,代碼里做了遞歸,但是遞歸的判定不嚴(yán)謹(jǐn),特殊的情況下(可能發(fā)生的事在未來某個(gè)時(shí)間一定會發(fā)生)會導(dǎo)致棧溢出,做了一些優(yōu)化,應(yīng)該還ok。第三個(gè)問題是典型的goroutine泄露的問題,做一下優(yōu)化就好了。最終還想問django orm的一些細(xì)節(jié),但是這些細(xì)節(jié)我真忘了(tornado我還能掰扯兩句)。整體上這次二面跟之前還是不太一樣的,不拘于某個(gè)固定的答案。
聲網(wǎng)-后端工程師
一面面試官更偏向于運(yùn)維工作,談下來感覺跟我之前在團(tuán)隊(duì)內(nèi)的職責(zé)類似,也是個(gè)trouble shooter。先做了自我介紹,問簡歷里提到的golang high cpu問題是如何診斷解決的,那就從監(jiān)控發(fā)現(xiàn)high cpu說到pprof,再說到flame graph(性能診斷利器),發(fā)現(xiàn)了pprint使用反射的機(jī)制來輸出pb結(jié)構(gòu),問怎么優(yōu)化,答pb直接輸出是看不了的,是二進(jìn)制,看了pb相關(guān)的庫,發(fā)現(xiàn)有pbToJson的實(shí)現(xiàn),采用上線之后解決了high cpu的問題,問pbToJson的實(shí)現(xiàn)原理,我沒太了解過,但是根據(jù)自己的理解作出了答案,pb其實(shí)已經(jīng)定義好了,在生成pb到go文件的時(shí)候就已經(jīng)知道,pb字段對應(yīng)到j(luò)son的字段了,沒必要再通過反射來獲取。問對k8s的整體架構(gòu)的了解,多大的集群,答5個(gè)節(jié)點(diǎn),架構(gòu)從namespace、ingress、service、deployment談到hpa等。問鏡像如何打包,怎么優(yōu)化打包時(shí)間,答使用docker build,引用初始公共鏡像作為一層,然后拷貝,執(zhí)行安裝依賴、C庫的命令,設(shè)置啟動(dòng)命令行最終構(gòu)建出來一個(gè)鏡像,優(yōu)化(優(yōu)化可以很泛,但是本質(zhì)上脫離不了cpu、磁盤io、網(wǎng)絡(luò)、算法幾大類)的話我只答了依賴的鏡像可以使用小版本的。問k8s日志如何采集,答用相關(guān)的k8s組件捕獲pod標(biāo)準(zhǔn)輸出發(fā)送到日志服務(wù),然后再切分持久化建索引等等,問prometheus的語法,答雖然了解點(diǎn),但用的很少,忘了。問k8s集群如何診斷問題、如何抓包,答我們應(yīng)用集成了錯(cuò)誤采集的服務(wù),所以應(yīng)用層的問題直接就知道了,但是更底層的需要通過抓包來解決的我們暫時(shí)還沒遇到過。最后聊到了語言的問題,他們公司用的node,我雖然也寫過js,但也僅是寫過,另外我也診斷優(yōu)化過java寫的搜索引擎性能問題,雖然當(dāng)時(shí)有點(diǎn)令人頭禿,對于語言我還是開放性的。一面過了。
二面視頻面試,習(xí)慣了問各種語言的語法和庫的面試,這次有點(diǎn)不一樣。問如何計(jì)算一個(gè)點(diǎn)是否在橢圓內(nèi),這個(gè)比較簡單,按橢圓定義的公式就好了。問如何確定一個(gè)點(diǎn)是否正好在橢圓的邊上,這個(gè)跟面試官做了一些討論,包括用一個(gè)大橢圓一個(gè)小橢圓中間的陰影來確定這個(gè)點(diǎn),小橢圓可能需要重新計(jì)算焦點(diǎn),也可以用其它近似的算法來確定。三問有了解過哪些內(nèi)存管理相關(guān)的知識,無關(guān)語言的,和面試官從棧內(nèi)存聊到堆內(nèi)存的分配、內(nèi)存逃逸、逃逸的條件、為什么優(yōu)先分配棧內(nèi)存、引用計(jì)數(shù)和標(biāo)記清除各自解決了什么問題以及優(yōu)缺點(diǎn)、循環(huán)引用的解決方法、內(nèi)存碎片的解決方案內(nèi)存對齊、小對象的堆內(nèi)存管理、通用對象預(yù)分配內(nèi)存、python和go各自的內(nèi)存管理方案,這次面試關(guān)于內(nèi)存相關(guān)的技術(shù)全部抖出來了,體驗(yàn)還不錯(cuò),還想和面試官聊下其它如linux、數(shù)據(jù)庫相關(guān)的技術(shù),時(shí)間不夠,就先這樣了。本次面試官在內(nèi)存管理方面所掌握的技術(shù)應(yīng)該是比較深刻的,有的細(xì)節(jié)我都沒get到。二面應(yīng)該是過了。
字節(jié)-飛書考勤
首先做了自我介紹,然后針對我的項(xiàng)目問了很多問題。問簡歷上提到的搜索引擎優(yōu)化是如何優(yōu)化的,答首先描述了下我們線上的問題,隨著公司服務(wù)用戶增多,某天晚上做活動(dòng)的時(shí)候由于請求過多導(dǎo)致搜索服務(wù)掛掉了,我搭建了副本做了壓測,然后通過jstack診斷到solr阻塞在fieldCache讀寫上了,做了一些優(yōu)化,1是調(diào)整每分鐘hardCommit一次,這樣不用每次提交都打開IndexSearcher,所以頻繁重新打開IndexSeacher會需要頻繁預(yù)熱緩存,2是在打開新的IndexSearcher并使用前,對Searcher執(zhí)行幾次查詢,預(yù)熱緩存,3是優(yōu)化搜索語句,如fq=A and B 與fq=A&fq=B是不一樣的,如果A條件比較通用B條件變化較大,可以使用后面的查詢最大化利用filterCache。問數(shù)據(jù)庫優(yōu)化的案例,答線上的數(shù)據(jù)庫問題其實(shí)很復(fù)雜,并不是單純的優(yōu)化慢SQL就好了,當(dāng)然慢SQL的優(yōu)化也經(jīng)常做,一個(gè)實(shí)際的案例是某天做活動(dòng)線上掛了,發(fā)現(xiàn)mysql CPU很高,通過采集查詢語句分組分析,了解到是某個(gè)查詢在10分鐘內(nèi)掃描了上億的行數(shù),這種單個(gè)查詢命中了幾十到上百行左右,并不是慢查詢,但是活動(dòng)期間的掃描行數(shù)的總量是非常恐怖的,當(dāng)時(shí)處理的方式先block住這條查詢,讓線上服務(wù)其它功能正常下來,然后加緩存(適合的就是好的)上線,移除block,面試官問每次取到了上百行的數(shù)據(jù)那索引是不是建錯(cuò)了,區(qū)分度不高,當(dāng)時(shí)沒回答這個(gè)問題,詳細(xì)的查詢語句其實(shí)已經(jīng)忘了,但是后面想了下如果對于百萬行級別的表,查到上百行的索引區(qū)分度還是可以的,如果不建索引走全表那肯定是不能接受的。然后還談到了優(yōu)化應(yīng)用層掃全表的效率,通過id來偏移,問如何優(yōu)化復(fù)合索引的掃全表,答二級索引也是有序的,直接用上次查到最后的一條記錄做偏移就好了。問context包有用到么有了解他的數(shù)據(jù)結(jié)構(gòu),答有的,大致了解過有父子context,父取消,所有子取消,里面還是用了channel,后面還問了一些問題,但是有的我沒get到面試官要問的點(diǎn),有的點(diǎn)可能也沒給到面試官想要的答案。算法題是層序遍歷的變種,卡了我一段時(shí)間,有點(diǎn)慌,不過最終還是解決了。一面未通過,不知道是不是因?yàn)樗惴}卡了很久。