Dubbo常见面试题与答案
Dubbo的基礎(chǔ)知識(shí)
Dubbo的核心架構(gòu)是怎樣的?
-
Registry:注冊(cè)中心。 負(fù)責(zé)服務(wù)地址的注冊(cè)與查找,服務(wù)的 Provider 和 Consumer 只在啟動(dòng)時(shí)與注冊(cè)中心交互。注冊(cè)中心通過長連接感知 Provider 的存在,在 Provider 出現(xiàn)宕機(jī)的時(shí)候,注冊(cè)中心會(huì)立即推送相關(guān)事件通知 Consumer;
-
Provider:服務(wù)提供者。 在它啟動(dòng)的時(shí)候,會(huì)向 Registry 進(jìn)行注冊(cè)操作,將自己服務(wù)的地址和相關(guān)配置信息封裝成 URL 添加到 ZooKeeper 中;
-
Consumer
:服務(wù)消費(fèi)者。 在它啟動(dòng)的時(shí)候,會(huì)向 Registry 進(jìn)行訂閱操作。訂閱操作會(huì)從 ZooKeeper 中獲取 Provider 注冊(cè)的 URL,并在 ZooKeeper 中添加相應(yīng)的監(jiān)聽器。
- 獲取到 Provider URL 之后,Consumer 會(huì)根據(jù)負(fù)載均衡算法從多個(gè) Provider 中選擇一個(gè) Provider 并與其建立連接,最后發(fā)起對(duì) Provider 的 RPC 調(diào)用;
- 如果 Provider URL 發(fā)生變更,Consumer 將會(huì)通過之前訂閱過程中在注冊(cè)中心添加的監(jiān)聽器,獲取到最新的 Provider URL 信息,進(jìn)行相應(yīng)的調(diào)整,比如斷開與宕機(jī) Provider 的連接,并與新的 Provider 建立連接;
- Consumer 與 Provider 建立的是長連接,且 Consumer 會(huì)緩存 Provider 信息,所以一旦連接建立,即使注冊(cè)中心宕機(jī),也不會(huì)影響已運(yùn)行的 Provider 和 Consumer;
-
Monitor:監(jiān)控中心。 用于統(tǒng)計(jì)服務(wù)的調(diào)用次數(shù)和調(diào)用時(shí)間。Provider 和 Consumer 在運(yùn)行過程中,會(huì)在內(nèi)存中統(tǒng)計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間,定時(shí)每分鐘發(fā)送一次統(tǒng)計(jì)數(shù)據(jù)到監(jiān)控中心。監(jiān)控中心在上面的架構(gòu)圖中并不是必要角色,監(jiān)控中心宕機(jī)不會(huì)影響 Provider、Consumer 以及 Registry 的功能,只會(huì)丟失監(jiān)控?cái)?shù)據(jù)而已。
為什么說Dubbo是基于URL驅(qū)動(dòng)的?
- URL 在 Dubbo 中被當(dāng)作是“公共的契約”。一個(gè) URL 可以包含非常多的擴(kuò)展點(diǎn)參數(shù),URL 作為上下文信息貫穿整個(gè)擴(kuò)展點(diǎn)設(shè)計(jì)體系;
- Dubbo 基于 URL驅(qū)動(dòng)的好處:
- 統(tǒng)一數(shù)據(jù)格式規(guī)范,讓交互變得簡單化;
- 使用URL作為方法參數(shù),便于參數(shù)擴(kuò)展,新參數(shù)只需要以k/v形式追加到URL即可,不需要改變?nèi)雲(yún)⒒蚍祷刂档臄?shù)據(jù)結(jié)構(gòu);
Dubbo的URL由哪些部分組成?
- 下面是Provider 注冊(cè)到 ZooKeeper 上的 URL 例子:
dubbo://172.17.32.91:20880/org.apache.dubbo.demo.DemoService ?anyhost=true&application=dubbo-demo-api-provider&dubbo=2.0.2 &interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync&pid=32508&release= &side=provider×tamp=1593253404714dubbo://172.17.32.91:20880/org.apache.dubbo.demo.DemoService ?anyhost=true&application=dubbo-demo-api-provider&dubbo=2.0.2 &interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync &pid=32508&release=&side=provider×tamp=1593253404714
- protocol:dubbo 協(xié)議;
- host/port:172.17.32.91:20880;
- path:org.apache.dubbo.demo.DemoService;
- parameters:參數(shù)鍵值對(duì),這里是問號(hào)后面的參數(shù)。
相較于JDK SPI而言,Dubbo SPI做了哪些改進(jìn)?
- JDK SPI 會(huì)一次性實(shí)例化擴(kuò)展點(diǎn)所有實(shí)現(xiàn),如果有擴(kuò)展實(shí)現(xiàn)初始化很耗時(shí),但如果沒用上也加載,會(huì)很浪費(fèi)資源,而Dubbo SPI可以按需進(jìn)行加載,實(shí)例化后會(huì)進(jìn)行緩存;
- Dubbo按照SPI配置文件的用途,將其分為了三個(gè)目錄:
- META-INF/services/:該目錄下的 SPI 配置文件用來兼容 JDK SPI ;
- META-INF/dubbo/:該目錄用于存放用戶自定義 SPI 配置文件;
- META-INF/dubbo/internal/:該目錄用于存放 Dubbo 內(nèi)部使用的 SPI 配置文件。
- Dubbo 將 SPI 配置文件改成了 KV 格式,key被稱為擴(kuò)展名,我們可以指定擴(kuò)展名來查找具體的實(shí)現(xiàn),從而實(shí)現(xiàn)按需加載;
- 擴(kuò)展名更利于我們排查異常,Dubbo SPI在拋出異常時(shí),會(huì)攜帶擴(kuò)展名信息,而不是簡單提升具體實(shí)現(xiàn)類無法加載,提升我們排查問題的效率。
Dubbo的擴(kuò)展點(diǎn)有哪些分類?
- 普通擴(kuò)展類:最基礎(chǔ)的,配置在SPI配置文件中的擴(kuò)展類實(shí)現(xiàn);
- 包裝擴(kuò)展類:Wrapper類是一種裝飾者模式,在構(gòu)造方法中傳入一個(gè)具體擴(kuò)展接口的實(shí)現(xiàn),屬于Dubbo的自動(dòng)包裝特性。在ExtensionLoader在加載擴(kuò)展時(shí),如果發(fā)現(xiàn)這個(gè)擴(kuò)展類包含其它擴(kuò)展點(diǎn)作為構(gòu)造函數(shù)參數(shù),則這個(gè)擴(kuò)展類就會(huì)被認(rèn)定為是Wrapper類;
- 自適應(yīng)擴(kuò)展類:一個(gè)擴(kuò)展接口會(huì)有多種實(shí)現(xiàn)類,具體使用哪個(gè)實(shí)現(xiàn)類可以不寫死在配置或代碼中,在運(yùn)行時(shí),通過傳入U(xiǎn)RL中的某些參數(shù)動(dòng)態(tài)確定,這屬于擴(kuò)展點(diǎn)的自適應(yīng)特性。
Dubbo的@Adaptive注解與@Activate注解的區(qū)別是什么?
- @Adaptive稱為自適應(yīng)擴(kuò)展點(diǎn)注解。自適應(yīng)擴(kuò)展指的是,一個(gè)擴(kuò)展接口往往會(huì)有多種實(shí)現(xiàn)類,因?yàn)镈ubbo是基于URL驅(qū)動(dòng),所以在運(yùn)行時(shí),通過傳入U(xiǎn)RL中的某些參數(shù)來動(dòng)態(tài)控制具體實(shí)現(xiàn);
- @Adaptive可以修飾類級(jí)別與方法級(jí)別:
- 修飾方法級(jí)別時(shí),Dubbo初始化擴(kuò)展點(diǎn)時(shí)會(huì)自動(dòng)生成和編譯一個(gè)動(dòng)態(tài)的Adaptive類,是一種動(dòng)態(tài)代理的模式,方法里會(huì)有一些抽象的通用邏輯,根據(jù)解析URL得到的信息,找到并調(diào)用真正的實(shí)現(xiàn)類;
- 修飾類級(jí)別時(shí),省略了生成動(dòng)態(tài)代理類的過程,由該類中決定具體實(shí)現(xiàn),可理解為是一種靜態(tài)代理的模式。另外對(duì)于同一個(gè)擴(kuò)展點(diǎn),類級(jí)別的Adaptive只能有一個(gè)。
- @Adaptive可以修飾類級(jí)別與方法級(jí)別:
- @Activate稱為自動(dòng)激活擴(kuò)展點(diǎn)注解。主要使用在有多個(gè)擴(kuò)展點(diǎn)實(shí)現(xiàn)、需要同時(shí)根據(jù)不同條件被激活的場景中,如Filter需要多個(gè)同時(shí)激活,因?yàn)槊總€(gè)Filter實(shí)現(xiàn)的是不同的功能;
- @Activate的參數(shù):
| String[] group() | URL中的分組如果匹配則激活 |
| String[] value() | URL中如果包含該key值,則會(huì)激活 |
| String[] before() | 填寫擴(kuò)展點(diǎn)列表,表示哪些擴(kuò)展點(diǎn)要在本擴(kuò)展點(diǎn)之前激活 |
| String[] after() | 表示哪些擴(kuò)展點(diǎn)需要在本擴(kuò)展點(diǎn)之后激活 |
| int order() | 排序信息 |
服務(wù)通信
如何設(shè)計(jì)一個(gè)rpc框架?
- 主要的模塊:
- protocol:簡易版 RPC 框架的自定義協(xié)議;
- serialization:提供了自定義協(xié)議對(duì)應(yīng)的序列化、反序列化的相關(guān)工具類;
- codec:提供了自定義協(xié)議對(duì)應(yīng)的編碼器和解碼器;
- transport:基于 Netty 提供了底層網(wǎng)絡(luò)通信的功能,其中會(huì)使用到 codec 包中定義編碼器和解碼器,以及 serialization 包中的序列化器和反序列化器;
- registry:基于 ZooKeeper 和 Curator 實(shí)現(xiàn)了簡易版本的注冊(cè)中心功能;
- proxy:使用 JDK 動(dòng)態(tài)代理實(shí)現(xiàn)了一層代理。
一次rpc請(qǐng)求的流程是怎樣的?
- Client 首先會(huì)調(diào)用本地的代理,也就是圖中的 Proxy;
- Client 端 Proxy 會(huì)按照協(xié)議(Protocol),將調(diào)用中傳入的數(shù)據(jù)序列化成字節(jié)流;
- 之后 Client 會(huì)通過網(wǎng)絡(luò),將字節(jié)數(shù)據(jù)發(fā)送到 Server 端;
- Server 端接收到字節(jié)數(shù)據(jù)之后,會(huì)按照協(xié)議進(jìn)行反序列化,得到相應(yīng)的請(qǐng)求信息;
- Server 端 Proxy 會(huì)根據(jù)序列化后的請(qǐng)求信息,調(diào)用相應(yīng)的業(yè)務(wù)邏輯;
- Server 端業(yè)務(wù)邏輯的返回值,也會(huì)按照上述邏輯返回給 Client 端。
序列化的意義是什么?
- 簡單來說,序列化是把對(duì)象的狀態(tài)信息轉(zhuǎn)化為可存儲(chǔ)或傳輸?shù)男问竭^程,也就是把對(duì)象轉(zhuǎn)化為字節(jié)序列的過程稱為對(duì)象的序列化。反序列化是序列化的逆向過程,把字節(jié)數(shù)組反序列化為對(duì)象。
Dubbo服務(wù)發(fā)布的流程是怎樣的?
- dubbo的service本質(zhì)是一個(gè)被Spring管理的ServiceBean,ServiceBean實(shí)現(xiàn)了眾多Spring提供的接口;
- afterPropertiesSet:解析配置;
- onApplicationEvent:執(zhí)行發(fā)布流程;
- 服務(wù)發(fā)布流程:
Dubbo服務(wù)引用的流程是怎樣的?
- Dubbo 的 consumer 會(huì)通過 ReferenceBean 實(shí)現(xiàn)服務(wù)引用;
- Dubbo 服務(wù)引用的時(shí)機(jī)有兩個(gè):
- 第一個(gè)是在 Spring 容器調(diào)用 ReferenceBean 的 afterPropertiesSet 方法時(shí)引用服務(wù);
- 第二個(gè)是在 ReferenceBean 對(duì)應(yīng)的服務(wù)被注入到其他類中時(shí)引用,而入口都是getObject方法。
- 服務(wù)引用流程:
Dubbo的Invoker是什么?
- Invoker 是Dubbo 的核心模型,其它模型都向它靠攏,或轉(zhuǎn)換成它,它代表一個(gè)可執(zhí)行體,可向它發(fā)起 invoke 調(diào)用,它有可能是一個(gè)本地的實(shí)現(xiàn),也可能是一個(gè)遠(yuǎn)程的實(shí)現(xiàn),也可能一個(gè)集群實(shí)現(xiàn);
- 在服務(wù)提供方,Invoker 用于調(diào)用服務(wù)提供類。在服務(wù)消費(fèi)方,Invoker 用于執(zhí)行遠(yuǎn)程調(diào)用。Invoker 是由 Protocol 實(shí)現(xiàn)類構(gòu)建而來。
在Dubbo中Proxy 和 Wrapper的作用是什么?
- Consumer 端的 Proxy 底層屏蔽了復(fù)雜的網(wǎng)絡(luò)交互、集群策略以及 Dubbo 內(nèi)部的 Invoker 等概念,提供給上層使用的是業(yè)務(wù)接口;
- Provider 端的 Wrapper 是將個(gè)性化的業(yè)務(wù)接口實(shí)現(xiàn),統(tǒng)一轉(zhuǎn)換成 Dubbo 內(nèi)部的 Invoker 接口實(shí)現(xiàn);
- 正是由于 Proxy 和 Wrapper 這兩個(gè)組件的存在,Dubbo 才能實(shí)現(xiàn)內(nèi)部接口和業(yè)務(wù)接口的無縫轉(zhuǎn)換。
集群
Dubbo的Directory(服務(wù)目錄)是什么?
- Directory中存儲(chǔ)了一些和服務(wù)提供者有關(guān)的信息,通過Directory,服務(wù)消費(fèi)者可獲取到服務(wù)提供者的信息,比如 ip、端口、服務(wù)協(xié)議等。通過這些信息,服務(wù)消費(fèi)者就可通過 Netty 等客戶端進(jìn)行遠(yuǎn)程調(diào)用。
- 一個(gè)服務(wù)集群中,provider的數(shù)量是會(huì)動(dòng)態(tài)變更的,Directory從注冊(cè)中心獲取provider的配置信息后,會(huì)為每條配置生成對(duì)應(yīng)的Invoker對(duì)象,因此Directory 可以看成是一組Invoker 的集合,它會(huì)隨著注冊(cè)中心的變化而動(dòng)態(tài)調(diào)整。
Dubbo Cluster的作用是什么?
- 在Dubbo體系中,集群模塊是服務(wù)提供者和服務(wù)消費(fèi)者的中間層,為服務(wù)消費(fèi)者屏蔽了服務(wù)提供者的情況,這樣服務(wù)消費(fèi)者就可以專心處理遠(yuǎn)程調(diào)用相關(guān)事宜。比如發(fā)請(qǐng)求,接受服務(wù)提供者返回的數(shù)據(jù)等;
- 集群 Cluster 用途是將多個(gè)服務(wù)提供者合并為一個(gè) Cluster Invoker,并將這個(gè) Invoker 暴露給服務(wù)消費(fèi)者。這樣一來,服務(wù)消費(fèi)者只需通過這個(gè) Invoker 進(jìn)行遠(yuǎn)程調(diào)用即可,至于具體調(diào)用哪個(gè)服務(wù)提供者,以及調(diào)用失敗后如何處理等問題,現(xiàn)在都交給集群模塊去處理。
Dubbo Cluster的工作流程是怎樣的?
- 第一個(gè)階段:服務(wù)消費(fèi)者初始化期間,集群 Cluster 實(shí)現(xiàn)類為服務(wù)消費(fèi)者創(chuàng)建 Cluster Invoker 實(shí)例;
- 第二個(gè)階段:
- 服務(wù)消費(fèi)者進(jìn)行遠(yuǎn)程調(diào)用時(shí),Cluster Invoker 首先會(huì)調(diào)用 Directory 的 list 方法列舉 Invoker 列表;
- 然后調(diào)用 Router 的 route 方法進(jìn)行路由,過濾掉不符合路由規(guī)則的 Invoker(例如黑名單過濾);
- 當(dāng)Cluster Invoker 拿到 Directory 返回的 Invoker 列表后,它會(huì)通過 LoadBalance 從 Invoker 列表中選擇一個(gè) Invoker,通過這個(gè)Invoker實(shí)例進(jìn)行遠(yuǎn)程調(diào)用。
Dubbo有哪些集群容錯(cuò)策略?
| Failover | 失敗自動(dòng)切換:當(dāng)出現(xiàn)請(qǐng)求失敗時(shí),會(huì)重試其它服務(wù)器??梢酝ㄟ^retries設(shè)置重試次數(shù),默認(rèn)為2次。該方式是dubbo默認(rèn)的容錯(cuò)機(jī)制,適用于讀操作或冪等的寫操作。 |
| Failfast | 快速失敗:當(dāng)請(qǐng)求失敗后,快速返回異常結(jié)果,不做任何重試。適用于非冪等接口。 |
| Failsafe | 失敗安全:當(dāng)請(qǐng)求出現(xiàn)異常時(shí),直接忽略異常。適用于佛系調(diào)用場景,即不關(guān)心調(diào)用是否成功,也不想影響外層的調(diào)用,例如不重要的日志同步等。 |
| Failback | 失敗自動(dòng)恢復(fù):請(qǐng)求失敗后,會(huì)自動(dòng)記錄在失敗隊(duì)列中,并由一個(gè)定時(shí)線程池定時(shí)重試。適用于一些異步請(qǐng)求或最終一致性的請(qǐng)求。 |
| Forking | 并行調(diào)用:同時(shí)調(diào)用多個(gè)相同的服務(wù),只要有一個(gè)返回,則立即返回結(jié)果,可通過forks設(shè)置并行數(shù)。適用于某些對(duì)實(shí)時(shí)性要求極高的調(diào)用上,但也會(huì)浪費(fèi)更多的資源。 |
| Broadcast | 廣播調(diào)用:廣播調(diào)用所有可用的服務(wù),任意一個(gè)節(jié)點(diǎn)報(bào)錯(cuò)則報(bào)錯(cuò)。適用于服務(wù)測試。 |
| Available | 最簡單的調(diào)用:請(qǐng)求不會(huì)做負(fù)載均衡,遍歷所有服務(wù)列表,找到第一個(gè)可用的節(jié)點(diǎn),直接請(qǐng)求并返回,如果沒有可用節(jié)點(diǎn)則拋出異常。 |
Dubbo有哪些負(fù)載均衡策略?
| Random LoadBalance | 隨機(jī)可以按權(quán)重設(shè)置隨機(jī)概率,調(diào)用量越大分布月均勻 |
| RoundRobin LoadBalance | 輪詢可以根據(jù)權(quán)重設(shè)置輪詢比例。 |
| LeastActive LoadBalance | 最少活躍調(diào)用數(shù)根據(jù)活躍度進(jìn)行分配調(diào)用,使慢的提供者收到更少的請(qǐng)求,如果活躍數(shù)相同則隨機(jī)調(diào)用,活躍數(shù)是指調(diào)用前后的計(jì)數(shù)差。 |
| ConsistentHash LoadBalance | 一致性Hash相同參數(shù)的請(qǐng)求總是發(fā)到同一提供者,當(dāng)某臺(tái)提供者掛掉時(shí),基于虛擬節(jié)點(diǎn),相應(yīng)的請(qǐng)求會(huì)平攤到其它提供者,不會(huì)引起劇烈變動(dòng)。 |
限流、熔斷、降級(jí)
Dubbo是如何實(shí)現(xiàn)限流的?
- 通過Dubbo Service注解的executes屬性配置最大并行數(shù);
- 限流的具體邏輯由ExecuteLimitFilter實(shí)現(xiàn),本質(zhì)是基于信號(hào)量控制并發(fā)數(shù);
Dubbo中如何實(shí)現(xiàn)熔斷?
- Dubbo沒有提供自動(dòng)熔斷策略;
Dubbo是否支持降級(jí)?
- 可以通過Reference注解中的mock屬性返回默認(rèn)值。
性能調(diào)優(yōu)
如何根據(jù)參數(shù)對(duì)Dubbo進(jìn)行調(diào)優(yōu)?
- Schema 配置參考手冊(cè) | Apache Dubbo
總結(jié)
以上是生活随笔為你收集整理的Dubbo常见面试题与答案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人民日报智慧媒体研究院与第四范式合资成立
- 下一篇: 回首2020,我们砥砺前行