《我想進(jìn)大廠》之Dubbo普普通通9問
這是面試專題系列第四篇,Dubbo系列。Dubbo本身并不復(fù)雜,而且官方文檔寫的非常清楚詳細(xì),面試中dubbo的問題一般不會很多,從分層到工作原理、負(fù)載均衡策略、容錯機(jī)制、SPI機(jī)制基本就差不多了,最大的一道大題一般就是怎么設(shè)計一個RPC框架了,但是如果你工作原理分層都搞明白了這個問題其實(shí)也就相當(dāng)于回答了不是嗎。
說說Dubbo的分層?
從大的范圍來說,dubbo分為三層,business業(yè)務(wù)邏輯層由我們自己來提供接口和實(shí)現(xiàn)還有一些配置信息,RPC層就是真正的RPC調(diào)用的核心層,封裝整個RPC的調(diào)用過程、負(fù)載均衡、集群容錯、代理,remoting則是對網(wǎng)絡(luò)傳輸協(xié)議和數(shù)據(jù)轉(zhuǎn)換的封裝。
劃分到更細(xì)的層面,就是圖中的10層模式,整個分層依賴由上至下,除開business業(yè)務(wù)邏輯之外,其他的幾層都是SPI機(jī)制。

能說下Dubbo的工作原理嗎?
服務(wù)啟動的時候,provider和consumer根據(jù)配置信息,連接到注冊中心register,分別向注冊中心注冊和訂閱服務(wù)
register根據(jù)服務(wù)訂閱關(guān)系,返回provider信息到consumer,同時consumer會把provider信息緩存到本地。如果信息有變更,consumer會收到來自register的推送
consumer生成代理對象,同時根據(jù)負(fù)載均衡策略,選擇一臺provider,同時定時向monitor記錄接口的調(diào)用次數(shù)和時間信息
拿到代理對象之后,consumer通過代理對象發(fā)起接口調(diào)用
provider收到請求后對數(shù)據(jù)進(jìn)行反序列化,然后通過代理調(diào)用具體的接口實(shí)現(xiàn)

為什么要通過代理對象通信?
主要是為了實(shí)現(xiàn)接口的透明代理,封裝調(diào)用細(xì)節(jié),讓用戶可以像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程方法,同時還可以通過代理實(shí)現(xiàn)一些其他的策略,比如:
1、調(diào)用的負(fù)載均衡策略
2、調(diào)用失敗、超時、降級和容錯機(jī)制
3、做一些過濾操作,比如加入緩存、mock數(shù)據(jù)
4、接口調(diào)用數(shù)據(jù)統(tǒng)計
說說服務(wù)暴露的流程?
在容器啟動的時候,通過ServiceConfig解析標(biāo)簽,創(chuàng)建dubbo標(biāo)簽解析器來解析dubbo的標(biāo)簽,容器創(chuàng)建完成之后,觸發(fā)ContextRefreshEvent事件回調(diào)開始暴露服務(wù) 通過ProxyFactory獲取到invoker,invoker包含了需要執(zhí)行的方法的對象信息和具體的URL地址 再通過DubboProtocol的實(shí)現(xiàn)把包裝后的invoker轉(zhuǎn)換成exporter,然后啟動服務(wù)器server,監(jiān)聽端口 最后RegistryProtocol保存URL地址和invoker的映射關(guān)系,同時注冊到服務(wù)中心

說說服務(wù)引用的流程?
服務(wù)暴露之后,客戶端就要引用服務(wù),然后才是調(diào)用的過程。
首先客戶端根據(jù)配置文件信息從注冊中心訂閱服務(wù)
之后DubboProtocol根據(jù)訂閱的得到provider地址和接口信息連接到服務(wù)端server,開啟客戶端client,然后創(chuàng)建invoker
invoker創(chuàng)建完成之后,通過invoker為服務(wù)接口生成代理對象,這個代理對象用于遠(yuǎn)程調(diào)用provider,服務(wù)的引用就完成了

有哪些負(fù)載均衡策略?
加權(quán)隨機(jī):假設(shè)我們有一組服務(wù)器 servers = [A, B, C],他們對應(yīng)的權(quán)重為 weights = [5, 3, 2],權(quán)重總和為10。現(xiàn)在把這些權(quán)重值平鋪在一維坐標(biāo)值上,[0, 5) 區(qū)間屬于服務(wù)器 A,[5, 8) 區(qū)間屬于服務(wù)器 B,[8, 10) 區(qū)間屬于服務(wù)器 C。接下來通過隨機(jī)數(shù)生成器生成一個范圍在 [0, 10) 之間的隨機(jī)數(shù),然后計算這個隨機(jī)數(shù)會落到哪個區(qū)間上就可以了。
最小活躍數(shù):每個服務(wù)提供者對應(yīng)一個活躍數(shù) active,初始情況下,所有服務(wù)提供者活躍數(shù)均為0。每收到一個請求,活躍數(shù)加1,完成請求后則將活躍數(shù)減1。在服務(wù)運(yùn)行一段時間后,性能好的服務(wù)提供者處理請求的速度更快,因此活躍數(shù)下降的也越快,此時這樣的服務(wù)提供者能夠優(yōu)先獲取到新的服務(wù)請求。
一致性hash:通過hash算法,把provider的invoke和隨機(jī)節(jié)點(diǎn)生成hash,并將這個 hash 投射到 [0, 2^32 - 1] 的圓環(huán)上,查詢的時候根據(jù)key進(jìn)行md5然后進(jìn)行hash,得到第一個節(jié)點(diǎn)的值大于等于當(dāng)前hash的invoker。

加權(quán)輪詢:比如服務(wù)器 A、B、C 權(quán)重比為 5:2:1,那么在8次請求中,服務(wù)器 A 將收到其中的5次請求,服務(wù)器 B 會收到其中的2次請求,服務(wù)器 C 則收到其中的1次請求。
集群容錯方式有哪些?
Failover Cluster失敗自動切換:dubbo的默認(rèn)容錯方案,當(dāng)調(diào)用失敗時自動切換到其他可用的節(jié)點(diǎn),具體的重試次數(shù)和間隔時間可用通過引用服務(wù)的時候配置,默認(rèn)重試次數(shù)為1也就是只調(diào)用一次。
Failback Cluster快速失敗:在調(diào)用失敗,記錄日志和調(diào)用信息,然后返回空結(jié)果給consumer,并且通過定時任務(wù)每隔5秒對失敗的調(diào)用進(jìn)行重試
Failfast Cluster失敗自動恢復(fù):只會調(diào)用一次,失敗后立刻拋出異常
Failsafe Cluster失敗安全:調(diào)用出現(xiàn)異常,記錄日志不拋出,返回空結(jié)果
Forking Cluster并行調(diào)用多個服務(wù)提供者:通過線程池創(chuàng)建多個線程,并發(fā)調(diào)用多個provider,結(jié)果保存到阻塞隊(duì)列,只要有一個provider成功返回了結(jié)果,就會立刻返回結(jié)果
Broadcast Cluster廣播模式:逐個調(diào)用每個provider,如果其中一臺報錯,在循環(huán)調(diào)用結(jié)束后,拋出異常。
了解Dubbo SPI機(jī)制嗎?
SPI 全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機(jī)制,本質(zhì)是將接口實(shí)現(xiàn)類的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件,加載實(shí)現(xiàn)類,這樣可以在運(yùn)行時,動態(tài)為接口替換實(shí)現(xiàn)類。
Dubbo也正是通過SPI機(jī)制實(shí)現(xiàn)了眾多的擴(kuò)展功能,而且dubbo沒有使用java原生的SPI機(jī)制,而是對齊進(jìn)行了增強(qiáng)和改進(jìn)。
SPI在dubbo應(yīng)用很多,包括協(xié)議擴(kuò)展、集群擴(kuò)展、路由擴(kuò)展、序列化擴(kuò)展等等。
使用方式可以在META-INF/dubbo目錄下配置:
key=com.xxx.value
然后通過dubbo的ExtensionLoader按照指定的key加載對應(yīng)的實(shí)現(xiàn)類,這樣做的好處就是可以按需加載,性能上得到優(yōu)化。
如果讓你實(shí)現(xiàn)一個RPC框架怎么設(shè)計?
首先需要一個服務(wù)注冊中心,這樣consumer和provider才能去注冊和訂閱服務(wù) 需要負(fù)載均衡的機(jī)制來決定consumer如何調(diào)用客戶端,這其中還當(dāng)然要包含容錯和重試的機(jī)制 需要通信協(xié)議和工具框架,比如通過http或者rmi的協(xié)議通信,然后再根據(jù)協(xié)議選擇使用什么框架和工具來進(jìn)行通信,當(dāng)然,數(shù)據(jù)的傳輸序列化要考慮 除了基本的要素之外,像一些監(jiān)控、配置管理頁面、日志是額外的優(yōu)化考慮因素。
那么,本質(zhì)上,只要熟悉一兩個RPC框架,就很容易想明白我們自己要怎么實(shí)現(xiàn)一個RPC框架。
推薦閱讀
騰訊 Git 規(guī)范出爐,寫給開發(fā)者的指南!
最棒 Spring Boot 干貨總結(jié)(超詳細(xì),建議收藏)
