有情懷,有乾貨,微信搜尋【三太子敖丙】關注這個不一樣的程式設計師。
本文 GitHub https://github.com/JavaFamily 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。
前言
Dubbo 整體介紹的差不多了,今天就開始面試環節了,我會列舉一些常見的 Dubbo 面試題,只會抓著重的,一些太簡單的我就不提了。
不僅僅給你面試題的答案,也會剖析面試官問這個問題的原因,也就是他的內心活動。
想從你這裡問出什麼?想要什麼答案?想挖什麼坑給你跳?
開始表演
知道什麼是 RPC 麼?
一般面試官會以這樣的問題來切入、熱場,畢面試也是循序漸進的過程,所以你也不用太心急一開始就芭芭拉說一堆,要抓住關鍵點簡單闡述先。
而且面試官能從這個問題鑑定出你平日的工作內容會不會連 RPC 都沒接觸過,會不會就只是一條龍的 Spring MVC ?
確實有很多同學沒接觸過 RPC ,也很正常比如一些外包或者一些小專案都接觸不到的,不過平日接觸不到和你不知道這個東西是兩個概念。
能從側面反映出這個人工作之餘應該不怎麼學習,連 RPC 都不知道,所以怎麼都說不過去,基本上要涼涼,對你的初始印象就差了,除非你能從後面有亮眼的表現。
答:RPC 就是 Remote Procedure Call,遠端過程呼叫,它相對應的是本地過程呼叫。
那為什麼要有 RPC,HTTP 不好麼?
這時候面試官就開始追問了。
這個問題其實很有意思,有些面試官可能自己不太清楚,然後以為自己很清楚,所以問出這個問題,還有一種是真的清楚,問這個問題是為了讓你跳坑裡。
因為 RPC 和 HTTP 就不是一個層級的東西,所以嚴格意義上這兩個沒有可比性,也不應該來作比較,而題目問的就是把這兩個作為比較了。
HTTP 只是傳輸協議,協議只是規範了一定的交流格式,而且 RPC 是早於 HTTP 的,所以真要問也是問有 RPC 為什麼還要 HTTP。
RPC 對比的是本地過程呼叫,是用來作為分散式系統之間的通訊,它可以用 HTTP 來傳輸,也可以基於 TCP 自定義協議傳輸。
所以你要先提出這兩個不是一個層級的東西,沒有可比性,然後再表現一下,可以說 HTTP 協議比較冗餘,所以 RPC 大多都是基於 TCP 自定義協議,定製化的才是最適合自己的。
當然也有基於 HTTP 協議的 RPC 框架,畢竟 HTTP 是公開的協議,比較通用,像 HTTP2 已經做了相應的壓縮了,而且系統之間的呼叫都在內網,所以說影響也不會很大。
這波回答下來,面試官會覺得你有點東西,開始對你有點興趣了,要開始深入你了。
說說你對 Dubbo 的瞭解?
面試官會先問個大點的問題,然後從你的回答中找到一些突破口來深入問,所以這個問題其實挺開放性的,你可以從歷史的發展來答,也可以從整體架構來答。
如果從歷史發展的角度來答,說明你平日裡也是挺關注一些開源軟體的,側面也能體現你的對開源的擁抱。
如果從總體架構答,毋庸置疑肯定也是可以的,建議先淺顯的說,等著追問。
歷史發展,這個其實丙之前文章已經提到了:
Dubbo 是阿里巴巴開源的一個基於 Java 的 RPC 框架,中間沉寂了一段時間,但在 2017 年阿里巴巴又重啟了對 Dubbo 維護。
並且在 2018 年和 噹噹的 Dubbox 進行了合併,進入 Apache 孵化器,在 2019 年畢業正式成為 Apache 頂級專案。
目前 Dubbo 社群主力維護的是 2.6.x 和 2.7.x 兩大版本,2.6.x 版本主要是 bug 修復和少量功能增強為準,是穩定版本。
2.7.5 版本的釋出被 Dubbo 認為是里程碑式的版本釋出,支援 gRPC,並且效能提升了 30%(這裡不瞭解gRPC 和為什麼效能提升的話就別說了,別給自己挖坑)。
最新的 3.0 版本往雲原生方向上探索著。
注意了,如果對歷史各個版本不太熟,也不知道最新的版本要幹啥就別往這方向答了,運氣好點就是面試官自己也不太瞭解,他可能不會問,運氣背點就追問了。
總體架構,上面也提到了先淺顯的說,等追問,因為面試官如果懂,他肯定會問深入,如果不懂你芭芭拉一堆他無感的。
你就簡單的提一下現在這幾個角色。
節點 | 角色說明 |
---|---|
Consumer | 需要呼叫遠端服務的服務消費方 |
Registry | 註冊中心 |
Provider | 服務提供方 |
Container | 服務執行的容器 |
Monitor | 監控中心 |
比如, Dubbo 總體分了以上這麼幾個角色,分別的作用是xxxx。
這裡停頓下看下面試官的反應,如果沒搭話,就繼續說大致的流程。
首先服務提供者 Provider 啟動然後向註冊中心註冊自己所能提供的服務。
服務消費者 Consumer 啟動向註冊中心訂閱自己所需的服務。然後註冊中心將提供者元資訊通知給 Consumer, 之後 Consumer 因為已經從註冊中心獲取提供者的地址,因此可以通過負載均衡選擇一個 Provider 直接呼叫 。
之後服務提供方後設資料變更的話註冊中心會把變更推送給服務消費者。
服務提供者和消費者都會在記憶體中記錄著呼叫的次數和時間,然後定時的傳送統計資料到監控中心。
到這基本上就差不多了,如果之前看過丙的 Dubbo 系列文章的話,那就算看過原始碼了,肯定對一系列過程很清晰了,所以在適當的時機可以說自己看過 Dubbo 原始碼。
眾所周知,看過原始碼肯定是加分項,所以這點是要提的。
面試官一聽,好傢伙看過原始碼是吧,來說說。
接下來就開始連擊了。
看過原始碼,那說下服務暴露的流程?
服務的暴露起始於 Spring IOC 容器重新整理完畢之後,會根據配置引數組裝成 URL, 然後根據 URL 的引數來進行本地或者遠端呼叫。
會通過 proxyFactory.getInvoker
,利用 javassist 來進行動態代理,封裝真的實現類,然後再通過 URL 引數選擇對應的協議來進行 protocol.export,預設是 Dubbo 協議。
在第一次暴露的時候會呼叫 createServer 來建立 Server,預設是 NettyServer。
然後將 export 得到的 exporter 存入一個 Map 中,供之後的遠端呼叫查詢,然後會向註冊中心註冊提供者的資訊。
基本上就是這麼個流程,說了這些差不多了,太細的誰都記住不。
看過原始碼,那說下服務引入的流程?
服務的引入時機有兩種,第一種是餓漢式,第二種是懶漢式。
餓漢式就是載入完畢就會引入,懶漢式是隻有當這個服務被注入到其他類中時啟動引入流程,預設是懶漢式。
會先根據配置引數組裝成 URL ,一般而言我們都會配置的註冊中心,所以會構建 RegistryDirectory 向註冊中心註冊消費者的資訊,並且訂閱提供者、配置、路由等節點。
得知提供者的資訊之後會進入 Dubbo 協議的引入,會建立 Invoker ,期間會包含 NettyClient,來進行遠端通訊,最後通過 Cluster 來包裝 Invoker,預設是 FailoverCluster,最終返回代理類。
說這麼多差不多了,關鍵的點都提到了。
切忌不要太過細,不要把你知道的都說了,這樣會抓不住重點,比如上面的流程你要插入,引入的三種方式:本地引入、直連遠端引入、通過註冊中心引入。
然後再分別說本地引入怎樣的,芭芭拉的就會很亂,所以面試的時候是需要刪減的,要直擊重點。
其實真實說的應該比我上面說的還要精簡點才行,我是怕大家不太清楚說的稍微詳細了一些。
看過原始碼,那說下服務呼叫的流程?
呼叫某個介面的方法會呼叫之前生成的代理類,然後會從 cluster 中經過路由的過濾、負載均衡機制選擇一個 invoker 發起遠端呼叫,此時會記錄此請求和請求的 ID 等待服務端的響應。
服務端接受請求之後會通過引數找到之前暴露儲存的 map,得到相應的 exporter ,然後最終呼叫真正的實現類,再組裝好結果返回,這個響應會帶上之前請求的 ID。
消費者收到這個響應之後會通過 ID 去找之前記錄的請求,然後找到請求之後將響應塞到對應的 Future 中,喚醒等待的執行緒,最後消費者得到響應,一個流程完畢。
關鍵的就是 cluster、路由、負載均衡,然後 Dubbo 預設是非同步的,所以請求和響應是如何對應上的。
之後可能還會追問 Dubbo 非同步轉同步如何實現的之類的,在丙之前文章裡面都說了,忘記的同學可以回去看看。
知道什麼是 SPI 嘛?
這又是一個方向了,從上面的回答中,不論是從 Dubbo 協議,還是 cluster ,什麼 export 方法等等無處不是 SPI 的影子,所以如果是問 Dubbo 方面的問題,問 SPI 是毋庸置疑的,因為原始碼裡 SPI 無處不在,而且 SPI 也是 Dubbo 可擴充套件性的基石。
所以這個題目沒什麼套路,直接答就行。
SPI 是 Service Provider Interface,主要用於框架中,框架定義好介面,不同的使用者有不同的需求,因此需要有不同的實現,而 SPI 就通過定義一個特定的位置,Java SPI 約定在 Classpath 下的 META-INF/services/ 目錄裡建立一個以服務介面命名的檔案,然後檔案裡面記錄的是此 jar 包提供的具體實現類的全限定名。
所以就可以通過介面找到對應的檔案,獲取具體的實現類然後載入即可,做到了靈活的替換具體的實現類。
為什麼 Dubbo 不用 JDK 的 SPI,而是要自己實現?
問這個問題就是看你有沒有深入的瞭解,或者自己思考過,不是死板的看原始碼,或者看一些知識點。
很多點是要思考的,不是書上說什麼就是什麼,你要知道這樣做的理由,有什麼好處和壞處,這很容易看出一個人是死記硬背還是有自己的思考。
答:因為 Java SPI 在查詢擴充套件實現類的時候遍歷 SPI 的配置檔案並且將實現類全部例項化,假設一個實現類初始化過程比較消耗資源且耗時,但是你的程式碼裡面又用不上它,這就產生了資源的浪費。
因此 Dubbo 就自己實現了一個 SPI,給每個實現類配了個名字,通過名字去檔案裡面找到對應的實現類全限定名然後載入例項化,按需載入。
這答出來就加分了,面試官心裡在拍手了,不錯不錯有點東西。
Dubbo 為什麼預設用 Javassist
上面你回答 Dubbo 用 Javassist 動態代理,所以很可能會問你為什麼要用這個代理,可能還會引申出 JDK 的動態代理、ASM、CGLIB。
所以這也是個注意點,如果你不太清楚的話上面的回答就不要扯到動態代理了,如果清楚的話那肯定得提,來誘導面試官來問你動態代理方面的問題,這很關鍵。
面試官是需要誘導的,畢竟他也想知道你優秀的方面到底有多優秀,你也取長補短,雙贏雙贏。
來回答下為什麼用 Javassist,很簡單,就是快,且位元組碼生成方便。
ASM 比 Javassist 更快,但是沒有快一個數量級,而Javassist 只需用字串拼接就可以生成位元組碼,而 ASM 需要手工生成,成本較高,比較麻煩。
如果讓你設計一個 RPC 框架,如何設計?
面試官都很喜歡問這類問題,來考驗候選人的設計能力,和平日有無全方面的瞭解過一個框架。
如果你平時沒有思考,沒有往這方面想過答出來的東西就會沒有條理性,會顯得雜亂無章,不過你也不用慌張,不用想的很全面,答的很細緻,沒有必要,面試官要的是那些關鍵的重點。
你可以從底層向上開始說起。
首先需要實現高效能的網路傳輸,可以採用 Netty 來實現,不用自己重複造輪子,然後需要自定義協議,畢竟遠端互動都需要遵循一定的協議,然後還需要定義好序列化協議,網路的傳輸畢竟都是二進位制流傳輸的。
然後可以搞一套描述服務的語言,即 IDL(Interface description language),讓所有的服務都用 IDL 定義,再由框架轉換為特定程式語言的介面,這樣就能跨語言了。
此時最近基本的功能已經有了,但是隻是最基礎的,工業級的話首先得易用,所以框架需要把上述的細節對使用者進行遮蔽,讓他們感覺不到本地呼叫和遠端呼叫的區別,所以需要代理實現。
然後還需要實現叢集功能,因此的要服務發現、註冊等功能,所以需要註冊中心,當然細節還是需要遮蔽的。
最後還需要一個完善的監控機制,埋點上報呼叫情況等等,便於運維。
這樣一個 RPC 框架的雛形就差不多了。
最後
Dubbo 系列就到此結束了,其實還是有很多細節的,如果要寫肯定還是有很多可以寫的。
不過整體脈絡都理清楚了,之後的修行還是得靠大家自己多多努力。
面試題肯定不止這一些,面試題是問不完的,真實的面試肯定是抓住你回答的點來深挖,所以我也模擬不了,我只能告訴你大致關鍵點,和揣摩一下面試官的心理活動。
當面試官問你的時候你可以試著去揣摩,看看他到底想要問什麼,這很關鍵。
面試的時候不要慌,你和麵試官是平等的,而且面試官不一定你厲害,還有面試有時候就是看運氣了,面試失敗了也不要氣餒,換一家就好了,有時候就是氣場不和,這很正常。
加油。
我是敖丙,你知道的越多,你不知道的越多,感謝各位人才的:點贊、收藏和評論,我們下期見!
文章持續更新,可以微信搜一搜「 三太子敖丙 」第一時間閱讀,回覆【資料】有我準備的一線大廠面試資料和簡歷模板,本文 GitHub https://github.com/JavaFamily 已經收錄,有大廠面試完整考點,歡迎Star。