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