《面試八股文》之Dubbo17卷
微信公眾號:moon聊技術(shù)
關(guān)注選擇“ 星標 ”, 重磅干貨,第一 時間送達!
[如果你覺得文章對你有幫助,歡迎關(guān)注,在看,點贊,轉(zhuǎn)發(fā)]

前言
雖然金三銀四過了,但是金九銀十馬上就要到了,還不快快準備起來?
今天就開啟《面試八股文》系列的第一版-RPC王者Dubbo,moon 在后續(xù)的《面試八股文》系列還將繼續(xù)推出mysql,spring,并發(fā),redis,kafka,zookeeper等一系列文章。
當然大家有什么好的建議也可以通過公眾號或者個人微信和我交流。
每天一個知識點
不要背,要理解,大家不要夸我內(nèi)卷了
目錄
1.Dubbo是什么?RPC又是什么?
2. Dubbo能做什么?
3.能說下Dubbo的總體的調(diào)用過程嗎?
4.說說Dubbo 支持哪些協(xié)議,每種協(xié)議的應用場景和優(yōu)缺點
5.Dubbo中都用到哪些設計模式?
6.如果Dubbo中provider提供的服務由多個版本怎么辦?
7.服務暴露的流程是怎么樣的?
8.服務引用的流程是怎么樣的?
9.Dubbo的注冊中心有哪些?
10.聊聊Dubbo SPI機制?
11.Dubbo的SPi和JAVA的SPI有什么區(qū)別?
12.有哪些負載均衡策略?
13.集群容錯方式有哪些?
14.說說Dubbo的分層?
15.服務提供者能實現(xiàn)失效踢出是什么原理?
16.為什么要通過代理對象通信??
17.怎么設計一個RPC框架?
1.Dubbo是什么?RPC又是什么?
Dubbo是一個分布式服務框架,致力于提供高性能和透明化的RPC遠程服務調(diào)用方案,以及SOA服務治理方案。
RPC(Remote Procedure Call)—遠程過程調(diào)用,它是一種通過網(wǎng)絡從遠程計算機程序上請求服務,而不需要了解底>層網(wǎng)絡技術(shù)的協(xié)議。RPC協(xié)議假定某些傳輸協(xié)議的存在,如TCP或UDP,為通信程序之間攜帶信息數(shù)據(jù)。在OSI網(wǎng)絡>通信模型中,RPC跨越了傳輸層和應用層。RPC使得開發(fā)包括網(wǎng)絡分布式多程序在內(nèi)的應用程序更加容易。RPC采用客戶機/服務器模式。請求程序就是一個客戶機,而服務提供程序就是一個服務器。首先,客戶機調(diào)用進程發(fā)>送一個有進程參數(shù)的調(diào)用信息到服務進程,然后等待應答信息。在服務器端,進程保持睡眠狀態(tài)直到調(diào)用信息到達為>止。當一個調(diào)用信息到達,服務器獲得進程參數(shù),計算結(jié)果,發(fā)送答復信息,然后等待下一個調(diào)用信息,最后,客戶>端調(diào)用進程接收答復信息,獲得進程結(jié)果,然后調(diào)用執(zhí)行繼續(xù)進行。有多種 RPC模式和執(zhí)行。

我們用一種通俗易懂的語言解釋它,遠程調(diào)用就是本地機器調(diào)用遠程機器的一個方法,遠程機器返回結(jié)果的過程。
為什么要這么做?
主要原因是由于單臺服務的性能已經(jīng)無法滿足我們了,在這個流量劇增的時代,只有多臺服務器才能支撐起來現(xiàn)有的用戶體系,
而在這種體系下,服務越來越多,逐漸演化出了現(xiàn)在這種微服務化的RPC框架。
2. Dubbo能做什么?
Dubbo的核心功能主要包含:

遠程通訊:dubbo-remoting模塊, 提供對多種基于長連接的NIO框架抽象封裝,包括多種線程模型,序列化,以及“請求-響應”模式的信息交換方式。 集群容錯: 提供基于接口方法的透明遠程過程調(diào)用,包括多協(xié)議支持,以及軟負載均衡,失敗容錯,地址路由,動態(tài)配置等集群支持。 自動發(fā)現(xiàn): 基于注冊中心目錄服務,使服務消費方能動態(tài)的查找服務提供方,使地址透明,使服務提供方可以平滑增加或減少機器。
3.能說下Dubbo的總體的調(diào)用過程嗎?
調(diào)用過程圖:

1.Proxy持有一個Invoker對象,使用Invoker調(diào)用 2.之后通過Cluster進行負載容錯,失敗重試 3.調(diào)用Directory獲取遠程服務的Invoker列表 4.負載均衡 用戶配置了路由規(guī)則,則根據(jù)路由規(guī)則過濾獲取到的Invoker列表 用戶沒有配置路由規(guī)則或配置路由后還有很多節(jié)點,則使用LoadBalance方法做負載均衡,選用一個可以調(diào)用的Invoker 5.經(jīng)過一個一個過濾器鏈,通常是處理上下文、限流、計數(shù)等。 6.會使用Client做數(shù)據(jù)傳輸 7.私有化協(xié)議的構(gòu)造(Codec) 8.進行序列化 9.服務端收到這個Request請求,將其分配到ThreadPool中進行處理 10.Server來處理這些Request 11.根據(jù)請求查找對應的Exporter 12.之后經(jīng)過一個服務提供者端的過濾器鏈 13.然后找到接口實現(xiàn)并真正的調(diào)用,將請求結(jié)果返回
4.說說Dubbo 支持哪些協(xié)議,每種協(xié)議的應用場景和優(yōu)缺點

1.dubbo 單一長連接和 NIO 異步通訊,適合大并發(fā)小數(shù)據(jù)量的服務調(diào)用,以及消費者遠大于提供者。傳輸協(xié)議 TCP,異步,Hessian 序列化
2.rmi 采用 JDK 標準的 rmi 協(xié)議實現(xiàn),傳輸參數(shù)和返回參數(shù)對象需要實現(xiàn)Serializable 接口,使用 java 標準序列化機制,使用阻塞式短連接,傳輸數(shù)據(jù)包大小混合,消費者和提供者個數(shù)差不多,可傳文件,傳輸協(xié)議 TCP。多個短連接,TCP 協(xié)議傳輸,同步傳輸,適用常規(guī)的遠程服務調(diào)用和 rmi 互 操作。在依賴低版本的 Common-Collections 包,java 序列化存在安全漏洞
3.webservice 基于 WebService 的遠程調(diào)用協(xié)議,集成 CXF 實現(xiàn),提供和原生 WebService 的互操作。多個短連接,基于 HTTP 傳輸,同步傳輸,適用系統(tǒng)集成和跨語言調(diào)用;
4.http 基于 Http 表單提交的遠程調(diào)用協(xié)議,使用 Spring 的 HttpInvoke 實 現(xiàn)。多個短連接,傳輸協(xié)議 HTTP,傳入?yún)?shù)大小混合,提供者個數(shù)多于消 費者,需要給應用程序和瀏覽器 JS 調(diào)用
5.hessian 集成 Hessian 服務,基于 HTTP 通訊,采用 Servlet 暴露服務,Dubbo 內(nèi)嵌 Jetty 作為服務器時默認實現(xiàn),提供與 Hession 服務互操作。多個短連接,同步 HTTP 傳輸,Hessian 序列化,傳入?yún)?shù)較大,提供者大于消費者,提供者壓力較大,可傳文件;
6.memcache 基于 memcached 實現(xiàn)的 RPC 協(xié)議
7.redis 基于 redis 實現(xiàn)的 RPC 協(xié)議
5.Dubbo中都用到哪些設計模式?

責任鏈模式:
責任鏈模式在Dubbo中發(fā)揮的作用舉足輕重,就像是Dubbo框架的骨架。Dubbo的調(diào)用鏈組織是用責任鏈模式串連起來的。責任鏈中的每個節(jié)點實現(xiàn)Filter接口,然后由ProtocolFilterWrapper,將所有Filter串連起來。Dubbo的許多功能都是通過Filter擴展實現(xiàn)的,比如監(jiān)控、日志、緩存、安全、telnet以及RPC本身都是。
觀察者模式:
Dubbo中使用觀察者模式最典型的例子是RegistryService。消費者在初始化的時候回調(diào)用subscribe方法,注冊一個觀察者,如果觀察者引用的服務地址列表發(fā)生改變,就會通過NotifyListener通知消費者。此外,Dubbo的InvokerListener、ExporterListener 也實現(xiàn)了觀察者模式,只要實現(xiàn)該接口,并注冊,就可以接收到consumer端調(diào)用refer和provider端調(diào)用export的通知。
修飾器模式:
Dubbo中還大量用到了修飾器模式。比如ProtocolFilterWrapper類是對Protocol類的修飾。在export和refer方法中,配合責任鏈模式,把Filter組裝成責任鏈,實現(xiàn)對Protocol功能的修飾。其他還有ProtocolListenerWrapper、 ListenerInvokerWrapper、InvokerWrapper等。
工廠方法模式:
CacheFactory的實現(xiàn)采用的是工廠方法模式。CacheFactory接口定義getCache方法,然后定義一個AbstractCacheFactory抽象類實現(xiàn)CacheFactory,并將實際創(chuàng)建cache的createCache方法分離出來,并設置為抽象方法。這樣具體cache的創(chuàng)建工作就留給具體的子類去完成。
抽象工廠模式:
ProxyFactory及其子類是Dubbo中使用抽象工廠模式的典型例子。ProxyFactory提供兩個方法,分別用來生產(chǎn)Proxy和Invoker(這兩個方法簽名看起來有些矛盾,因為getProxy方法需要傳入一個Invoker對象,而getInvoker方法需要傳入一個Proxy對象,看起來會形成循環(huán)依賴,但其實兩個方式使用的場景不一樣)。AbstractProxyFactory實現(xiàn)了ProxyFactory接口,作為具體實現(xiàn)類的抽象父類。然后定義了JdkProxyFactory和JavassistProxyFactory兩個具體類,分別用來生產(chǎn)基于jdk代理機制和基于javassist代理機制的Proxy和Invoker。
適配器模式:
為了讓用戶根據(jù)自己的需求選擇日志組件,Dubbo自定義了自己的Logger接口,并為常見的日志組件(包括jcl, jdk, log4j, slf4j)提供相應的適配器。并且利用簡單工廠模式提供一個LoggerFactory,客戶可以創(chuàng)建抽象的Dubbo自定義Logger,而無需關(guān)心實際使用的日志組件類型。在LoggerFactory初始化時,客戶通過設置系統(tǒng)變量的方式選擇自己所用的日志組件,這樣提供了很大的靈活性。
代理模式:
Dubbo consumer使用Proxy類創(chuàng)建遠程服務的本地代理,本地代理實現(xiàn)和遠程服務一樣的接口,并且屏蔽了網(wǎng)絡通信的細節(jié),使得用戶在使用本地代理的時候,感覺和使用本地服務一樣。
6.如果Dubbo中provider提供的服務由多個版本怎么辦?
可以直接通過Dubbo配置中的version版本來控制多個版本即可。
比如:
<dubbo:service interface="com.xxxx.rent.service.IDemoService" ref="iDemoServiceFirst" version="1.0.0"/>
<dubbo:service interface="com.xxxx.rent.service.IDemoService" ref="iDemoServiceSecond" version="1.0.1"/>
老版本 version=1.0.0, 新版本version=1.0.1
7.服務暴露的流程是怎么樣的?

1.通過ServiceConfig解析標簽,創(chuàng)建dubbo標簽解析器來解析dubbo的標簽,容器創(chuàng)建完成之后,觸發(fā)ContextRefreshEvent事件回調(diào)開始暴露服務
2.通過proxyFactory.getInvoker方法,并利用javassist或DdkProxyFactory來進行動態(tài)代理,將服務暴露接口封裝成invoker對象,里面包含了需要執(zhí)行的方法的對象信息和具體的URL地址。
3.再通過DubboProtocol的實現(xiàn)把包裝后的invoker轉(zhuǎn)換成exporter,
4.然后啟動服務器server,監(jiān)聽端口
5.最后RegistryProtocol保存URL地址和invoker的映射關(guān)系,同時注冊到服務中心

8.服務引用的流程是怎么樣的?
1.首先客戶端根據(jù)config文件信息從注冊中心訂閱服務,首次會全量緩存到本地,后續(xù)的更新會監(jiān)聽動態(tài)更新到本地。
2.之后DubboProtocol根據(jù)provider的地址和接口信息連接到服務端server,開啟客戶端client,然后創(chuàng)建invoker
3.之后通過invoker為服務接口生成代理對象,這個代理對象用于遠程調(diào)用provider,至此完成了服務引用

9.Dubbo的注冊中心有哪些?

Zookeeper、Redis、Multicast、Simple 等都可以作為Dubbo的注冊中心
10.聊聊Dubbo SPI機制?
SPI(Service Provider Interface),是一種服務發(fā)現(xiàn)機制,其實就是將結(jié)構(gòu)的實現(xiàn)類寫入配置當中,在服務加載的時候?qū)⑴渲梦募毺帲虞d實現(xiàn)類,這樣就可以在運行的時候,動態(tài)的幫助接口替換實現(xiàn)類。
Dubbo的SPI其實是對java的SPI進行了一種增強,可以按需加載實現(xiàn)類之外,增加了 IOC 和 AOP 的特性,還有自適應擴展機制。
SPI在dubbo應用很多,包括協(xié)議擴展、集群擴展、路由擴展、序列化擴展等等。
Dubbo對于文件目錄的配置分為了三類。
1.META-INF/services/ 目錄:該目錄下的 SPI 配置文件是為了用來兼容 Java SPI 。 2.META-INF/dubbo/ 目錄:該目錄存放用戶自定義的 SPI 配置文件。
key=com.xxx.xxx
3.META-INF/dubbo/internal/ 目錄:該目錄存放 Dubbo 內(nèi)部使用的 SPI 配置文件。
11.Dubbo的SPi和JAVA的SPI有什么區(qū)別?

Java Spi
Java SPI 在查找擴展實現(xiàn)類的時候遍歷 SPI 的配置文件并且將實現(xiàn)類全部實例化
Dubbo Spi
1,對 Dubbo 進行擴展,不需要改動 Dubbo 的源碼 2,延遲加載,可以一次只加載自己想要加載的擴展實現(xiàn)。 3,增加了對擴展點 IOC 和 AOP 的支持,一個擴展點可以直接 setter 注入其它擴展點。 4,Dubbo 的擴展機制能很好的支持第三方 IoC 容器,默認支持 Spring Bean。
12.有哪些負載均衡策略?
1.加權(quán)隨機:比如我們有三臺服務器[A, B, C],給他們設置權(quán)重為[4, 5, 6],然后講這三個數(shù)平鋪在水平線上,和為15。
然后在15以內(nèi)生成一個隨機數(shù),0~4是服務器A,4~9是服務器B,9~15是服務器C

2.最小活躍數(shù):每個服務提供者對應一個活躍數(shù) active,初始情況下,所有服務提供者活躍數(shù)均為0。每收到一個請求,活躍數(shù)加1,完成請求后則將活躍數(shù)減1。在服務運行一段時間后,性能好的服務提供者處理請求的速度更快,因此活躍數(shù)下降的也越快,此時這樣的服務提供者能夠優(yōu)先獲取到新的服務請求。

3.一致性hash:
首先求出memcached服務器(節(jié)點)的哈希值,并將其配置到0~2的32次方的圓(continuum)上。 然后采用同樣的方法求出存儲數(shù)據(jù)的鍵的哈希值,并映射到相同的圓上。 然后從數(shù)據(jù)映射到的位置開始順時針查找,將數(shù)據(jù)保存到找到的第一個服務器上。如果超過2的32次方仍然找不到服務器,就會保存到第一臺memcached服務器上。

4.加權(quán)輪詢:比如我們有三臺服務器[A, B, C],給他們設置權(quán)重為[4, 5, 6],那么假如總共有15次請求,那么會有4次落在A服務器,5次落在B服務器,6次落在C服務器。

13.集群容錯方式有哪些?
1.Failover Cluster失敗自動切換:dubbo的默認容錯方案,當調(diào)用失敗時自動切換到其他可用的節(jié)點,具體的重試次數(shù)和間隔時間可用通過引用服務的時候配置,默認重試次數(shù)為1是只調(diào)用一次。
2.Failback Cluster失敗自動恢復:在調(diào)用失敗,記錄日志和調(diào)用信息,然后返回空結(jié)果給consumer,并且通過定時任務每隔5秒對失敗的調(diào)用進行重試
3.Failfast Cluster快速失敗:只會調(diào)用一次,失敗后立刻拋出異常
4.Failsafe Cluster失敗安全:調(diào)用出現(xiàn)異常,記錄日志不拋出,返回空結(jié)果
5.Forking Cluster并行調(diào)用多個服務提供者:通過線程池創(chuàng)建多個線程,并發(fā)調(diào)用多個provider,結(jié)果保存到阻塞隊列,只要有一個provider成功返回了結(jié)果,就會立刻返回結(jié)果
6.Broadcast Cluster廣播模式:逐個調(diào)用每個provider,如果其中一臺報錯,在循環(huán)調(diào)用結(jié)束后,拋出異常。
14.說說Dubbo的分層?
分層圖:
從大的范圍來說,dubbo分為三層
business業(yè)務邏輯層由我們自己來提供接口和實現(xiàn)還有一些配置信息 RPC層就是真正的RPC調(diào)用的核心層,封裝整個RPC的調(diào)用過程、負載均衡、集群容錯、代理 remoting則是對網(wǎng)絡傳輸協(xié)議和數(shù)據(jù)轉(zhuǎn)換的封裝。
Service和Config兩層可以認為是API層,主要提供給API使用者,使用者只需要配置和完成業(yè)務代碼就可以了。
后面所有的層級是SPI層,主 要提供給擴展者使用主要是用來做Dubbo的二次開發(fā)擴展功能。
再劃分到更細的層面,就是圖中的10層模式。
15.服務提供者能實現(xiàn)失效踢出是什么原理?
服務失效踢出基于Zookeeper的臨時節(jié)點原理。
Zookeeper中節(jié)點是有生命周期的,具體的生命周期取決于節(jié)點的類型,節(jié)點主要分為持久節(jié)點(Persistent)和臨時節(jié)點(Ephemeral) 。
16.為什么要通過代理對象通信??

其實主要就是為了將調(diào)用細節(jié)封裝起來,將調(diào)用遠程方法變得和調(diào)用本地方法一樣簡單,還可以做一些其他方面的增強,比如負載均衡,容錯機制,過濾操作,調(diào)用數(shù)據(jù)的統(tǒng)計。
17.怎么設計一個RPC框架?
關(guān)于這個問題,其實核心考察點就是你對于RPC框架的理解,一個成熟的RPC框架可以完成哪些功能,其實當我們看過一兩個RPC框架后,就可以對這個問題回答個七七八八了,我們來舉個例子。

1.首先我們得需要一個注冊中心,去管理消費者和提供者的節(jié)點信息,這樣才會有消費者和提供才可以去訂閱服務,注冊服務。
2.當有了注冊中心后,可能會有很多個provider節(jié)點,那么我們肯定會有一個負載均衡模塊來負責節(jié)點的調(diào)用,至于用戶指定路由規(guī)則可以使一個額外的優(yōu)化點。
3.具體的調(diào)用肯定會需要牽扯到通信協(xié)議,所以需要一個模塊來對通信協(xié)議進行封裝,網(wǎng)絡傳輸還要考慮序列化。
4.當調(diào)用失敗后怎么去處理?所以我們還需要一個容錯模塊,來負責失敗情況的處理。
5.其實做完這些一個基礎的模型就已經(jīng)搭建好了,我們還可以有更多的優(yōu)化點,比如一些請求數(shù)據(jù)的監(jiān)控,配置信息的處理,日志信息的處理等等。
這其實就是一個比較基本的RPC框架的大體思路,大家有沒有g(shù)et到?
往期推薦
確定不勾搭一下moon嗎?
玩玩技術(shù),聊聊人生,看看生活,搞搞理想!
一起來吐槽職場吧~
