https://instant.1point3acres.cn/thread/776466
猴子也能懂的系統設計套路
按照之前instant.1point3acres.cn裡說到過的,和大家分享一下我對於senior到staff這個檔次的系統設計的看法。這個方面其實每個人都會有自己的總結,我的方法論可能也只是適用於我所見到過的公司,大家看一看作為一個參考就好。
TLDR:用Functional Requirement - Nonfunctional Requirement - Data Model / API - Diagram - Failure這個流程,加上充分的準備和知識廣度,去應對系統設計面試。
背景介紹
從剛畢業伊始16年的instant.1point3acres.cn,到20年底跳槽1point3acres.com,直到這次隨心所欲加面design(我還能打10個!),甚至可以說沉迷系統設計面試。我對於系統設計面試的瞭解也從術語層面(當年根本都不知道kv資料庫是啥,就推薦Riak,臉不臉紅吶),最終到達了“當我們面試系統設計時,我們在面試什麼”的程度。
因為我偏愛做產品,加上本身總在大公司的產品組(支付,廣告等等),本身工作內容裡是不會需要做分散式系統設計的,對於很多系統設計面試的考點其實都得靠自己去學習和歸納。同時自己之前幾年級別不高,所以並不能作為系統面試的面試官去實際探索系統設計面試。不過好在我可能因為剛畢業就被系統設計面試打擊過,就一直或多或少抱有了對於系統設計領域的好奇心(或者說是不服輸)。看到一些複雜的現存系統,就會想稍微搞明白到底架構是怎麼做的,有機會的話,還可以接觸到公司內那些知道為什麼要這麼做的人去學習一下。
下面的分享,可能對於常年做infra的小夥伴們來說並沒有太多的參考價值,主要是對於那些沒有太多相關係統經驗,或者說做infra面產品,做產品面infra的時候,需要在自己不擅長的系統領域做一些設計的小夥伴,希望能有提供一些思路,來幫助各位準備最適合自己的系統設計套路。
善事利器
一個順手的白板app
- 能夠面試時隨時分享一個連結給面試官。我個人用的是miro,不過有最多3個可編輯白板的限制。
- 按照個人喜好選擇,比如有人就喜歡用工具自帶的圖形,而不是手繪,那google drawing也可以。
- 面試前至少用白板app練習過所有常用功能,有些白板app自帶的額外功能很不錯用。
- 對蘋果筆有手勢適配(比如雙擊蘋果筆側邊可以從任意模式切到畫筆模式,再雙擊自動切到橡皮擦,然後就只在兩者之間切換)更好。
- 和recruiter事先確認過可以用這個白板app,絕大部分都是ok的。只要面試官那邊能夠匯出你最後的圖,或者截圖,就應該沒問題。
一套順手的白板工具
- 經典的就是ipad pro (11寸就夠,不需要13寸)+ 蘋果筆(2代最好)。surface套裝也可以,其他平板套裝也可以,看個人喜好。
- 螢幕重新整理率太低會寫起來很不順手,120hz會很舒適,所以上面推薦的是pro。預算緊張可以忽略這一點。
- 如果是臨時買的,也多花點心思練習一下在上面塗寫,適應起來需要不少的時間。可以考慮追加買橡膠筆套,紙質保護膜這些進一步提升書寫體驗。
一套穩定的VC配置
- 當你感覺你的面試官的聲音斷斷續續的時候,可能他感覺到的是一樣的問題。事先和朋友用對應面試的聊天工具測試下聲音穩定程度。
- 因為你在低頭塗寫的時候,聲音比畫面重要,所以可以的話弄一個比預設筆記本內建麥克風更好的麥克風吧。個人用的是blue那個經典的麥克風,但是哪怕是蘋果小白耳機(有線的那個)的音質都是可以的。
- 你永遠不知道你提到的某個你自以為很有價值的點,是不是因為音訊問題被面試官忽略了,所以這一點投入還是有必要的,外帶時不時和麵試官做個ack檢查。
- 至於什麼三點光源,DSLR攝像頭,綠布背景板這些提升畫面質量的,個人覺得肯定有比沒有好,但是就超出系統設計面試的範疇了。
學習材料
- 神書DDIA
不用多說,大家都在推薦,我也依然很推薦。但是即便是我個人,我大概目前閱讀進度也只有60%不到(而且是多遍),集中在1/2/3/5/6/7/8/9/11這幾章,其中9和11沒有深入看進去。和隔壁一些小夥伴說的一樣,書裡很多的理論證明,還有各種細節上的討論,比如phantom read的具體情況,又或者說serializability vs linearizability,其實對於準備系統面試來說,並不是非常有幫助。更多的反而可能是寫在各章summary裡的,那些對於名詞和術語的總結,還有對於為什麼某些東西在系統設計裡很重要的簡單分析。搭配這些,和一些網上的中文或者英文的讀書筆記,就能讓你對這些東西有一個比較合適的理解,所以在反覆閱讀的時候,我個人會先看summary,再回頭去看有哪些知識點我瞭解不足。
但是這本書本身,說到底也只是個入門,在時間允許的情況,其實每一章裡的小話題,都能擴充套件出來無窮無盡的細節。我本身會因為好奇,繼續找網上的相關討論資料,而且我還是偏好於比較好的中文資料,比如juejin.cn這篇博文,直接把DDIA裡面關於分散式事務的部分做了非常好的總結,搭配一下,我對DDIA的7/8/9這三章理解直接就飛躍了。而我個人覺得這三章是對於沒有做過相關分散式資料讀寫的小夥伴來說,最晦澀的三章。類似的其他博文,相信各位如果用自己不明白的關鍵字去中文或者英文網路搜尋,也能找到很不錯的。1point3acres.com可以作為一個引子。
除了讀書筆記外,當然也有很多影片類的對DDIA的總結資料,比如youtube.com。我個人比較喜歡自己搜一堆資料交叉閱讀來理解,但是應該也會有不少人比較偏好影片總結的模式。此處我想提到一個額外的影片資料,就是作者本人youtube.com,裡面有上傳他去年在劍橋大學的一個分散式系統課程(前8個課時是另外一個老師講的concurrency),有人搬運+機翻到了bilibili.com。內容方面並不對應DDIA,但是也濃縮了很多書裡的知識點非常值得閱讀。
最終的目的,並不是說吃透這本書裡的各種知識點然後對名詞和解釋倒背如流,而是能夠透過和其他學習資料結合起來,在腦子裡有個完整的思維導圖。可以閉上眼時,對於剛看完的某個系統設計的架構圖,對每一個部分的trade-off,可以腦內註解一樣去對應到DDIA書上的知識點,然後給出自己的複述(去解釋給別人聽)。相比你能延綿不絕地丟擲wal,lsm,htap,saga,tcc,2pc,2pl,zero copy,consistent hashing這些名詞加上簡單的解釋,面試官可能只是想要你談availability和transaction,以及為什麼需要這個。如果你實際工作裡就做到過這麼深入的的話,務必請深度討論,不過首先還是從基礎需求開始討論。
- github.com
- amazon.com
這兩個,在我看來就屬於,當你一邊讀DDIA,一邊不清楚這裡面的很多術語到底是怎麼套用到實際的系統設計裡的時候,可以作為輔助的材料。兩者都是在儘可能廣度優先的前提下,覆蓋了許多系統設計面試裡的考點和問題,然後提供了大量延展閱讀,比如一些著名技術系統的paper,,相關產品的公司engineering blog,亦或者是其他人提供的總結。
但是這兩個終究也只是為了覆蓋儘可能多的考點而存在的,下面我會提到,面試官一般心裡會有幾個點希望你踩到,但是你如果只是一股腦去踩遍自己能想到的所有點,反而會浪費寶貴的時間。兩者我覺得有用到一個就好,因為閱讀這兩個的過程裡,重點不是記住了材料裡面寫的東西,而是你能透過它給的一個案例,去做自己的搜尋,遍歷到關聯的學術paper,tech talk,fireside chat,技術文章(比如infoq的網站和ytb頻道,highscalability的網站以及youtube上各種散落的tech talk,國內的掘金和開發者頭條還有各種技術分享平臺等等),還有各大公司的engineering blog。在那基礎上,能夠透過閱讀這些延展材料,強化自己對於案例的理解,內化為自己理解過的對應案例的解決方案,萬萬不可照本宣科去硬記它的解決方案。
- educative.io / 各種網站上的素人design
educative.io我放在最後,並且單獨說,也是覺得應該挺多爭議的。我個人認為,對於初次接觸系統設計的人而言,這個課是有一定價值的,它算是比上面的資料更加用心幫你做了一個整理+入門,而且它最經典的tinyurl那幾節的分析,能讓你在短時間內理解到,系統設計時到底是在設計什麼。對於不同的常見例題,可能需要踩的點會有哪些。
但是我們來到senior-staff這個級別的系統設計面試的話,這些就夠了嗎?比起來說不夠,我甚至覺得它裡面的一些有點複製貼上意思的trade-off分析(多個不同案例的trade-off分析幾乎一樣),和它不分場景都上來先算capacity的做法,其實容易把人帶進溝裡。我這次面試前後加起來快20場系統面試,真的聊到grok裡那樣需要考慮每一條資料具體有多少,一個也沒有(有一個問到了大概是GB還是TB)。這個我後面也會聊到,capacity是有意義的,但是它的意義並不是說你具體算出來要存120TB,你知道是個TB級就足夠了。其次就是後面追加的新課之間的複製貼上感嚴重,動不動就上NoSQL等等,很明顯就是原作者沒有這方面的深度思考或者經驗,基於之前的內容在寫,並沒有對於新課主題系統的針對性分析。
因為一樣的原因,youtube或者一些獨立站上有不少看起來幾十萬閱讀量的up主上傳了很多系統設計的影片,也是深度不足且細節問題一堆,都是沒有太多實戰經驗的人,基於一個類似的模版反覆套用在不同系統上進行分析,最多會追加一兩個針對該系統的特色的設計。作為踩點來說有一點價值,但是本身真的那樣去面試是凶多吉少的。這方面我是基本都能找到對應系統的infoq演講,或者國內很多技術專家分享的類似系統的架構文章,所以不太需要依賴非專家的猜想式設計。
事前準備
- 練手面試
這個未必要是系統設計面試,因為下面我會單獨說。這個可以是你找朋友幫你mock,也可以是各種提供mock服務的公司,也可以是真的拿一些不想去的公司放在前面幾天來面試。主要的意義是讓你能夠習慣表達自己的臨時想法,相比coding這種你只要表達好程式碼思路,和behavior這種你能提前準備好相關回答的面試,系統設計需要你能隨時面對一個沒遇到過的開放式問題,一邊思考,一邊又能帶著面試官一起深入。這種把自己腦子裡想的,有趣的無趣的相關的跑題的想法,在面試壓力之下,能夠以合適甚至風趣的方式表達出來給面試官的能力,純手熟爾,無他。方法論層面,當然有各種書和影片,但是其實就和演講一樣,你學會了所有方法,剩下的就是255場練習了。
- 練手系統設計面試
我單獨拿這個出來說,是因為哪怕你學習到位,方法論總結到位,但是如果你要直接上陣,你還是不知道那套方法論在實踐的時候會變成什麼樣。design和implementation之間的差別,我們可太熟悉了。
我此處就要推薦一下interviewing.io這個可以提供mock系統設計面試的網站了,也感謝instant.1point3acres.cn提到了它。價格絕對不菲,不考慮團購價(4次及以上可以8折),指定大廠面試官要225,隨機大廠面試官150。但是如果你真的想提升自己的技巧,至少應該去book一次。我運氣很好,隨機book到了一個netflix的人,而且他的確做了不少系統設計的工作。在當時我已經做了很多準備,也提前練習過自己的一套流程的情況下,面試官一邊肯定了我這個套路非常好(perfecto,perfecto),一邊也給出了一些feedback,比如面對未知領域的系統設計,面試官的hint應該主動挖掘原因(交流加分),以及scale的討論(實際上我的流程裡的確安排了scale的部分,但是實戰和預演就是會差別很大,所以要練習)。
- 練手亂塗亂畫
把你要用的白板和vc工具提前自己習慣好,保證你到時候的精力都能專注在表達上,然後你能以最舒適的姿勢去操作你的白板app。透過一定程度的練習,你的字跡和圖案,不至於過於潦草讓人生草,不對,讓人無法理解。然後你可以總結一些自己習慣用的畫圖方式(比如資料庫用圓柱體,虛線代表非同步請求,等等),以及白板上哪裡放文字分析,哪裡放架構圖,預留多少空間給可能的額外要求等等。不要隨著面試深入,你要不停地擦擦改改,或者一小塊區域塞越來越多的資訊。
猴子也能懂的套路
此處允許我再次感謝一下instant.1point3acres.cn,因為我的套路法和他的可以說非常相似,也是在看到他的帖子之後,加上其他帖子和一些英文的分享,我恍然大悟出來的東西。和他一樣,一旦理解清楚,到目前為止的所有的積累就能活用起來,相比之下,20年年底的知識積累不會比現在差不多,但是沒有一個清晰的思路,就是隻能想到什麼說什麼,或者硬套見過的解決方案(這個是大忌)。
首先第一個要理解的,就是為什麼套路會如此有效,也就是我個人理解的,當我們系統設計面試時,我們到底在面試什麼 :系統設計考察的,嚴格來說並不是你對某些系統的深入瞭解,此處比如說一個地圖系統,你馬上把hilbert curve的演算法給他推演出來,或者一個youtube系統,你直接和他聊實時transcoding,面試官一來不是那麼感興趣,二來可能比你更懂這裡面的東西,反而能暴露你自己的臨時抱佛腳。一個有效的系統面試設計官,考察的是,就是你真的要做一個未知新系統時,你所表現出來的高階工程師的思考過程。誠然,如果你已經做過類似系統,那麼很多系統細節你能信手拈來,但是面試官也總有辦法考察到你沒有負責的部分,然後繼續考察你的思考過程。
你可以想想看,當你面對一個新系統的時候,你首先考慮了什麼要素,你要寫design doc的時候,你在寫什麼,你要和提需求的bd或者pm開會時,你會帶著什麼樣的問題去找他們,當你需要拉人做這個系統的時候,你是怎麼把需求變成分工的。你在工作裡肯定做過這樣的事,雖然未必目標是一個分散式事務系統,但是思考的過程其實不會差別特別大,在那之中蘊含的,就是(千層)套路,就是一個經驗豐富的工程師面對不同型別的需求,能夠把它翻譯成程式碼猴子也能懂的工程目標的能力。
以下我會按照我目前偏好的Functional Requirement - Nonfunctional Requirement - Data Model / API - Diagram - Failure這個套路來剖析。
Functional Requirement
搞清楚核心需求,主要的提問時間。這部分爭取在5分鐘以內解決
- 系統的使用者是誰,是使用者,還是其他服務,還是其他系統。
- 如何被使用,是有UI介面,還是定期從哪裡拿請求,是提供一個介面。
- 核心的容災需求是什麼樣,最不希望發生的錯誤是什麼樣的。
- 追問面試官自己整理的需求是否是核心的,避免錯過一些小而複雜的功能需求。
Non-functional requirement
次要的提問時間。系統需求之外,有哪些額外的需求需要滿足?按照你對系統的理解去offer自己心裡覺得最關鍵的幾個點,這部分也是5分鐘以內,別展開討論解決方案,就只是收集資訊。
- Consistency - 是否會有資料不一致導致的問題?是否能接受部分資料copy不一致?電商類肯定就要strong consistency,like button能做到read your own write就可以了,後臺型的服務eventual足矣。
- Availability - 這個系統要有多可用,1年能承受多少down time?3個9是1年8.8小時(1天88秒),4個9是1年53分鐘(1天8秒),5個9是1年5.3分鐘(1天1秒不到)。
- Reliability - 是否可以接受一定的錯誤率+可以重試?資料的durability也可以這裡談下。
- Performance/Throughput - 整體有多少使用者量,大機率多少活躍使用者,此處的使用者可以是其他系統。QPS大概有多少,peak factor是多少。
- Read/Write ratio - 讀為主還是寫為主,使用者使用pattern是否是非對稱的(比如微博),讀寫是否有seasonal/recency pattern(比如讀的都是最近寫的),這個會讓後面資料庫選型討論很方便。
- Scalability - 這個和上面的吞吐的區別是,可以展開問面試官希望這個系統有多scalable,因為這個概念本身其實是有一定模煳性的。單機百萬websocket和叢集數萬分散式事務都可以說scalable。
- Misc - 這個就要看具體系統,比如金融交易這些,idempotency就很重要,要提到。比如使用者facing的系統,latency就最好控制在200ms裡(先問latency,別自己主動offer,如果給了一個很大的值,就說明有很大的空間)。
- 等等 - 這些就需要自己透過上面的學習來總結,我能想到的上面這些肯定還只是其中一部分。
Data Model
上面兩個提問之後,就是你開始主導了。此處建議先問面試官偏好,說清楚自己接下來要聊data和api然後畫圖,data可以和API的順序進行調轉。這部分可能要10分鐘左右,但是也不要花太多時間。
基於上面的資訊,你心裡應該大概知道這個系統裡核心的幾個data model (物件導向程式設計101)是哪些方面。然後它們之間的互動,簡單粗暴可以用一個junction table去存互動的關係(就像一個edge,比如a like b),複雜點的就是transaction(a pay b)。把這些data model對應的“表”寫出來,此處你不用強調它是個sql表還是nosql的結構,就只說我們這個data model裡有哪些資訊。根據你的理解去填基本的那些資訊,比如某一種物件的id,對應的基本資訊,根據上面的需求產生的額外資訊(比如餐館系統,使用者表裡可以放會員狀態,打個比方)。基本data model完了,再聊下他們的關係表,此處依然不要說關係表是sql還是nosql,就說某個地方我們放著這個關係。但是如果是比較經典的事務型關係,比如交易,比如訂餐,比如發貨,並且你瞭解為什麼很多時候用NoSql類系統存這個資訊(寫為主,讀會帶著primary key,immutable records,量大,等等),那麼就可以主動提一下這一類資料適合放在比如說cassandra裡(因為我自己工作裡會用到cassandra)。
資料分類的過程中,不用追求完美,哪怕你提前看到過類似系統的設計方案,也不要上來就把n個field都給定義了,或者說你定義某個field要能對應到之前的需求。比如餐館系統,每2個小時的一張桌子可以算一條記錄,但是桌子本身應該有人數或者型別的資訊,這個會在談需求的時候談到。表與表之間產生聯絡(比如foreign key那種)一定要說,而且說到這個聯絡就可以自然地說indexing和sharding,或者說data locality你要怎麼做,然後延展到已經定義的field裡有哪些可以用來做composite key,secondary index,sorting key還有sharding key等等。同樣的,別過於深入,這一步重點不是系統的scalability,而是把data model定義清楚,為了後面服務。
API
這一部分根據面試官偏好,可能非常快,2分鐘就過,也可能有些人喜歡和你深入探討一個好的API設計。但是如果資料部分已經理得很清晰,我是覺得這部分一般最多也就5分鐘就能討論完。
首先都是自己主導,按照需求寫出基本的幾個API設計,輸入是什麼,輸出是什麼,他們是怎麼被call到的(同步,非同步,批次),以及會返回那幾類的結果(成功/失敗/有去重效果的成功或者失敗/等等)。然後同個API可以根據請求格式的不同有不同的行為。這方面一般來說不會談太複雜,因為時間關係不可能都涉及到,但是面試官會希望能看到你把已經談清楚的需求,清晰地反映到API層面,而不是漏掉了一些已經明確的需求(比如job scheduler裡能改變優先順序這種需求)。
此處一個潛在考點就是你對於API設計的經驗積累,能夠讓一套API圍繞一個資源或者目的來服務,而不是說你想到一個API就列舉一個API。cloud.google.com可以幫助你理解一些裡面的關鍵要素。REST API和RPC API的基礎知識可能會被考到,所以也最好了解清楚。
Diagram
好了,時間過半了,我們終於來到了畫圖部分。其實在這之前的很多討論,基本也都已經寫在了白板上。此處要重提一下就是,如果1小時面試,上面的4部分消耗20分鐘是沒問題的,如果是45分鐘,那麼就必須要壓縮,比如functional和nonfunctional放在一起快速過,API部分只提關鍵核心的部分等等,爭取在15分鐘這個時間點進入畫圖部分。
和其他帖子裡說的略微不同,我個人覺得,hotspot也好,是否要sharding也好,系統瓶頸分析也好,這些都是隻有把圖畫出來了,明白請求都是怎麼hit到哪裡的前提下,才好開始分析的。畢竟有時候,你套個cache,或者掛一層LB,實戰裡就已經很足夠,甚至都不用sharding那些。
然後很多同學在這一步可能就會遇到一個很常見的矛盾點 - 假設我知道某個系統大概是這麼做的,是否要直接畫成那樣。我的觀點是根據你的理解深度來判斷:你是否能夠defend自己這個架構?
比如說大家都知道推特類的系統要考慮pull和push,但是其實如果你深入看,類似的系統有做純pull的,有做純push的,也有做hybrid的,並沒有存在正確答案。push雖然有write amplifcation但是他的實現其實要簡單很多,反過來說pull也有一樣的看起來美好但是很麻煩的點(不只是單純資料庫壓力)。如果你碰巧只看過其中一類的架構圖,就原樣招唿上去,那麼面試官問起來你為什麼不用其他的方案,就會非常尷尬。但是如果你的理解廣度+深度能到比如zhuanlan.zhihu.com這樣,那麼你就可以隨意把自己知道的正確答案往上招乎了。
Failure
大部分情況下,面試應該就會在上面的部分消耗完時間,但是如果你特別嫻熟,飛快地把面試官的各種問題都解決了的話,那麼可能他就會問你,是否還有什麼別的想談的。此處其實是一個非常好的訊號,說明你已經cover到了他所有的考點,接下來就是純加分題了。我一般在這個地方,就會開始談整個系統可能的問題點,然後在一些極端情況下,會產生什麼樣的問題。也有其他同學覺得可以聊聊logging,monitoring,我本身也可以從系統故障的角度求聊這些。但是你要是有不同的偏好,我覺得是完全okay的,這個也可以算作是Other。
此時就是考驗你之前知識積累的廣度的時候了(抄答案的時候到了),你如果看過類似的系統的分析和部落格,就能想到一些很不錯而且不容易考慮到的點(比如對資料做了冷儲存的情況下,突然大量訪問老資料,又比如某個api突然被ddos導致系統故障)。此處就不太需要擔心被人考太深入,不像上面的pull push那樣如果準備不足貿然說一個方案反而會被問出問題來。打地鼠一樣,多打一個是一個。但是如果你到此刻才發現有些自己應該cover的關鍵點之前居然沒談到,那就走正式流程把這個點在最後幾分鐘裡好好說清楚,不用慌張,這個時間本來就是作為redundancy來給你的。
寫在最後
不論如何準備套路,和其他帖子寫的一樣,你都會碰到不按套路出牌的,和不吃你這套的。在實行套路的時候,也可能隨時被要求談不同的部分,這些都是沒辦法提前準備好,只能在大量的面試和練習之下,自然而然養成應對的本能。然後每一次面試結束,做好總結歸納,
系統設計面試,說到最後還是面試,還是讓對方在短時間內建立起你對的良好印象的一步。能夠應對面試官的需求,改變你的套路,也是交流溝通的重要一環。
希望能對苦於系統設計的各位,提供一些幫助。也歡迎各位隨時提問,知無不言,言無不盡。