Alibaba開源的分佈式服務框架:Dubbo是what?

1、認識dubbohtml

  Dubbo是Alibaba開源的分佈式服務框架,它最大的特色是按照分層的方式來架構,使用這種方式可使各個層之間解耦合(或者最大限度地鬆耦合)。從服務模型的角度來看,      Dubbo採用的是一種很是簡單的模型,要麼是提供方提供服務,要麼是消費方消費服務,因此基於這一點能夠抽象出服務提供方(Provider)和服務消費方(Consumer)兩個角色。關於註冊中心、協議支持、服務監控等內容,詳見後面描述。  Webservice也是一種服務框架,可是webservice並非分佈式的服務框架,他須要結合F5實現負載均衡。所以,dubbo除了能夠提供服務以外,還能夠實現軟負載均衡。它還提供了兩個功能Monitor 監控中心和調用中心。這兩個是可選的,須要單獨配置。前端

Dubbo是阿里巴巴SOA服務化治理方案的核心框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。其核心部分包含:java

  • 遠程通信: 提供對多種基於長鏈接的NIO框架抽象封裝,包括多種線程模型,序列化,以及「請求-響應」模式的信息交換方式。
  • 集羣容錯: 提供基於接口方法的透明遠程過程調用,包括多協議支持,以及軟負載均衡,失敗容錯,地址路由,動態配置等集羣支持。
  • 自動發現: 基於註冊中心目錄服務,使服務消費方能動態的查找服務提供方,使地址透明,使服務提供方能夠平滑增長或減小機器。
那麼,Dubbo能作什麼?
  • 透明化的遠程方法調用,就像調用本地方法同樣調用遠程方法,只需簡單配置,沒有任何API侵入。
  • 軟負載均衡及容錯機制,可在內網替代F5等硬件負載均衡器,下降成本,減小單點。
  • 服務自動註冊與發現,再也不須要寫死服務提供方地址,註冊中心基於接口名查詢服務提供者的IP地址,而且可以平滑添加或刪除服務提供者。

Dubbo產生的背景node

隨着互聯網的發展,網站應用的規模不斷擴大,常規的垂直應用架構已沒法應對,分佈式服務架構以及流動計算架構勢在必行,亟需一個治理系統確保架構有條不紊的演進。git

dubbo-architecture

  • 單一應用架構
    • 當網站流量很小時,只需一個應用,將全部功能都部署在一塊兒,以減小部署節點和成本。
    • 此時,用於簡化增刪改查工做量的數據訪問框架(ORM) 是關鍵。
  • 垂直應用架構
    • 當訪問量逐漸增大,單一應用增長機器帶來的加速度愈來愈小,將應用拆成互不相干的幾個應用,以提高效率。
    • 此時,用於加速前端頁面開發的Web框架(MVC) 是關鍵。
  • 分佈式服務架構
    • 當垂直應用愈來愈多,應用之間交互不可避免,將核心業務抽取出來,做爲獨立的服務,逐漸造成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。
    • 此時,用於提升業務複用及整合的分佈式服務框架(RPC) 是關鍵。
  • 流動計算架構
    • 當服務愈來愈多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增長一個調度中心基於訪問壓力實時管理集羣容量,提升集羣利用率。
    • 此時,用於提升機器利用率的資源調度和治理中心(SOA) 是關鍵。

Dubbo能夠知足的需求web

dubbo

在大規模服務化以前,應用可能只是經過RMI或Hessian等工具,簡單的暴露和引用遠程服務,經過配置服務的URL地址進行調用,經過F5等硬件進行負載均衡。面試

(1) 當服務愈來愈多時,服務URL配置管理變得很是困難,F5硬件負載均衡器的單點壓力也愈來愈大。redis

此時須要一個服務註冊中心,動態的註冊和發現服務,使服務的位置透明。算法

並經過在消費方獲取服務提供方地址列表,實現軟負載均衡和Failover,下降對F5硬件負載均衡器的依賴,也能減小部分紅本。spring

(2) 當進一步發展,服務間依賴關係變得錯蹤複雜,甚至分不清哪一個應用要在哪一個應用以前啓動,架構師都不能完整的描述應用的架構關係。

這時,須要自動畫出應用間的依賴關係圖,以幫助架構師理清理關係。

(3) 接着,服務的調用量愈來愈大,服務的容量問題就暴露出來,這個服務須要多少機器支撐?何時該加機器?

爲了解決這些問題,第一步,要將服務如今天天的調用量,響應時間,都統計出來,做爲容量規劃的參考指標。

其次,要能夠動態調整權重,在線上,將某臺機器的權重一直加大,並在加大的過程當中記錄響應時間的變化,直到響應時間到達閥值,記錄此時的訪問量,再以此訪問量乘以機器數反推總容量。

分佈式服務框架:
–高性能和透明化的RPC遠程服務調用方案
–SOA服務治理方案
-Apache MINA 框架基於Reactor模型通訊框架,基於tcp長鏈接
Dubbo缺省協議採用單一長鏈接和NIO異步通信,
適合於小數據量大併發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的狀況
分析源代碼,基本原理以下:
client一個線程調用遠程接口,生成一個惟一的ID(好比一段隨機字符串,UUID等),Dubbo是使用AtomicLong從0開始累計數字的
將打包的方法調用信息(如調用的接口名稱,方法名稱,參數值列表等),和處理結果的回調對象callback,所有封裝在一塊兒,組成一個對象object
向專門存放調用信息的全局ConcurrentHashMap裏面put(ID, object)
將ID和打包的方法調用信息封裝成一對象connRequest,使用IoSession.write(connRequest)異步發送出去
當前線程再使用callback的get()方法試圖獲取遠程返回的結果,在get()內部,則使用synchronized獲取回調對象callback的鎖, 再先檢測是否已經獲取到結果,若是沒有,而後調用callback的wait()方法,釋放callback上的鎖,讓當前線程處於等待狀態。
服務端接收到請求並處理後,將結果(此結果中包含了前面的ID,即回傳)發送給客戶端,客戶端socket鏈接上專門監聽消息的線程收到消息,分析結果,取到ID,再從前面的ConcurrentHashMap裏面get(ID),從而找到callback,將方法調用結果設置到callback對象裏。
監聽線程接着使用synchronized獲取回調對象callback的鎖(由於前面調用過wait(),那個線程已釋放callback的鎖了),再notifyAll(),喚醒前面處於等待狀態的線程繼續執行(callback的get()方法繼續執行就能拿到調用結果了),至此,整個過程結束。
一、當前線程怎麼讓它「暫停」,等結果回來後,再向後執行?
     答:先生成一個對象obj,在一個全局map裏put(ID,obj)存放起來,再用synchronized獲取obj鎖,再調用obj.wait()讓當前線程處於等待狀態,而後另外一消息監聽線程等到服 務端結果來了後,再map.get(ID)找到obj,再用synchronized獲取obj鎖,再調用obj.notifyAll()喚醒前面處於等待狀態的線程。
二、正如前面所說,Socket通訊是一個全雙工的方式,若是有多個線程同時進行遠程方法調用,這時創建在client server之間的socket鏈接上會有不少雙方發送的消息傳遞,先後順序也多是亂七八糟的,server處理完結果後,將結果消息發送給client,client收到不少消息,怎麼知道哪一個消息結果是原先哪一個線程調用的?
     答:使用一個ID,讓其惟一,而後傳遞給服務端,再服務端又回傳回來,這樣就知道結果是原先哪一個線程的了。

 

2、dubbo的架構思路

2.1 dubbo框架設計

dubbo官網的架構設計提供了一張總體的框架圖,10個層級看起來挺嚇人的。可是其核心總結起來就是:Microkernel + Plugin(微內核+插件)

 
微內核+插件機制

 

官網介紹的架構設計思想是兩點:

  • 採用 URL 做爲配置信息的統一格式,全部擴展點都經過傳遞 URL 攜帶配置信息;
  • 採用 Microkernel + Plugin 模式,Microkernel 只負責組裝 Plugin,Dubbo 自身的功能也是經過擴展點實現的,也就是 Dubbo 的全部功能點均可被用戶自定義擴展所替換。

對於第一點比較容易理解,由於是分佈式環境,各系統之間的參數傳遞基於URL來攜帶配置信息,全部的參數都封裝成 Dubbo 自定義的 URL 對象進行傳遞。URL 對象主要包括如下屬性:

String protocol
String host
int port
String path
Map<String, String> parameters 

第二點:系統裏抽象的各個模塊,每每有不少不一樣的實現方案,好的設計來講:模塊之間基於接口編程,模塊之間不對實現類進行硬編碼。一旦代碼裏涉及具體的實現類,就違反了可拔插的原則,若是須要替換一種實現,就須要修改代碼,例如:

if(參數=="dubbo"){ return new DubboProtocol(); } else if(參數 == "rmi"){ return new RMIProtocol(); } 

SPI的解決方案就呼之欲出了,一個接口對應有多個實現類的時候該怎樣指定麼?若是採用上述設計是很糟糕的,用if else來寫死本身的服務發現,若是新增一種協議則還須要去修改代碼,針對此類問題Java自己提供了spi機制,能夠作到服務發現和動態擴展,可是弊端就是一初始化就把全部實現類給加載進去,dubbo改進了spi並從新命名爲ExtensionLoader(擴展點機制),按照用戶配置來指定加載模塊,只須要約定一下路徑便可:

private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/"; 

這部分源碼能夠考察知識點很是多,對使用者來講是透明的,而精華卻良多,尤爲結合java-spi,jvm以及spring等多方面對比、借鑑,所以理論上能夠好好掌握,固然最好的學習方式就是按照極簡的思路來實現一個簡版RPC工具。

2.2dubbo原理、與Spring融合

dubbo是一個分佈式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。既然是分佈式那就意味着:一個業務分拆多個子業務,部署在不一樣的服務器上,既然各服務是部署在不一樣的服務器上,那服務間的調用就是要經過網絡通訊。既然涉及到了網絡通訊,那麼服務消費者調用服務以前,都要寫各類網絡請求,編解碼之類的相關代碼,明顯是很不友好的.dubbo所說的透明,就是指,讓調用者對網絡請求,編解碼之類的細節透明,讓咱們像調用本地服務同樣調用遠程服務,甚至感受不到本身在調用遠程服務。

public class ProxyFactory implements InvocationHandler { private Class interfaceClass; public ProxyFactory(Class interfaceClass) { this.interfaceClass = interfaceClass; } //返回代理對象,此處用泛型爲了調用時不用強轉,用Object須要強轉 public <T> T getProxyObject(){ return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),//類加載器 new Class[]{interfaceClass},//爲哪些接口作代理(攔截哪些方法) this);//(把這些方法攔截到哪處理) } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method); System.out.println("進行編碼"); System.out.println("發送網絡請求"); System.out.println("將網絡請求結果進行解碼並返回"); return null; } } 

項目引入dubbo的方法推薦用XML配置的方式引入,即使是老項目拆分改造,只要是Spring工程,這個都是比較好作的,能夠想象本身若是開發一箇中間件服務,若是把服務嵌入spring容器當中呢?做爲高級開發人員這個也是一個進階的既能項。XML 配置方式是基於 Spring 的 Schema 和 XML 擴展機制實現的。經過該機制,咱們能夠編寫本身的 Schema,並根據自定義的 Schema 自定義標籤來配置 Bean。

使用 Spring 的 XML 擴展機制有如下幾個步驟:

  • 定義 Schema(編寫 .xsd 文件)
  • 定義 JavaBean
  • 編寫 NamespaceHandler 和 BeanDefinitionParser 完成 Schema 解析
  • 編寫 spring.handlers 和 spring.schemas 文件串聯解析部件
  • 在 XML 文件中應用配置

最好的學習效果是能夠本身按照模板來同樣畫瓢來創做一個相似的xml配置。可參考《dubbo源碼解析-簡單原理、與spring融合》

2.3 服務發佈

服務的發佈總共作了如下幾件事,這個也能夠從日誌log上看出來:

  • 暴露本地服務
  • 暴露遠程服務
  • 啓動netty
  • 鏈接zookeeper
  • 到zookeeper註冊
  • 監聽zookeeper

貼出一張官方文檔的服務發佈圖


 
服務發佈

首先 ServiceConfig 類拿到對外提供服務的實際類 ref(如:HelloWorldImpl),而後經過 ProxyFactory 類的 getInvoker方法使用 ref 生成一個 AbstractProxyInvoker 實例,到這一步就完成具體服務到 Invoker 的轉化。接下來就是 Invoker 轉換到 Exporter 的過程。Dubbo 處理服務暴露的關鍵就在 Invoker 轉換到 Exporter 的過程,上圖中的紅色部分。
Dubbo 的實現
Dubbo 協議的 Invoker 轉爲 Exporter 發生在 DubboProtocol 類的 export 方法,它主要是打開 socket 偵聽服務,並接收客戶端發來的各類請求,通信細節由 Dubbo 本身實現。

上面摘抄了官方文檔(具體連接請戳),可能仍是有點抽象,實際上從代碼層面進行分析:
此處就是將本地的須要暴漏的方法以url形式做爲參數傳入 exportLocal()方法,url以前已經提到過包含了ip地址、端口、接口以及配置信息等。

 
關鍵步驟1-本地暴露

這時會執行到一個接口方法getInvoker(),這是一個註解了@Adaptive的方法,該方法的具體實現類是運行中生成動態編譯的Adaptive類,把java編譯出來的動態類貼出來debug以下,恍然大悟,原來他就是幾個if判斷,來告訴程序我這個url參數配置的是哪一種協議,我如今就動態的去調用這個擴展點服務(dubbo-spi),動態編譯的好處就是不用將代碼寫死,在協議會擴展的狀況下,我根據你配置的協議來動態的生成個人extensionLoader,再來加載我所須要的Invoker。

 
關鍵步驟2-getInvoker()方法

上圖引用的是本地服務的暴露執行,如果遠程服務的暴露,arg2參數的開頭則會是registry://192.168.0.1:2181/com.alibaba.dubbo.** / **。從exporter對象裏包含的invoker屬性能夠看出,invoker包含的攜帶ip、端口、接口以及配置信息的url。

 
關鍵步驟3-invoker信息

 

如今開始進入到遠程服務暴露的過程,通常來講這部分是應用和考察最多的點,經過配置的協議將服務暴露給外部調用。dubbo所支持的協議有多重,默認推薦dubbo協議,因而在動態代理的時候會生成Protocol$Adpative代理類,該代理類實現了RPC 協議接口,再經過擴展機制將服務加載進來。

 
關鍵步驟4-Protocol$Adpative代理類

加載了實現類後方法會順着調用鏈路進入到dubbo協議中的export()方法中來,能夠再DubboProtocol類中設置斷點觀察方法執行,此處完成了一個綁定,將暴露的接口+DubboExporter進行關聯放入map中緩存。

 
關鍵步驟5-DubboProtocol

後面的步驟再也不一一展開來說,愈來愈貼近底層和網絡通訊,咱們在調用dubbo接口的時候dubbo都爲了咱們作了這樣的工做,可是對開發人員來講都是透明無感知的:

  • exchange 信息交換層。封裝請求響應模式,同步轉異步,以 Request, Response 爲中心。
  • transport 網絡傳輸層:抽象 mina 和 netty 爲統一接口,以 Message 爲中心。
  • serialize 數據序列化層:可複用的一些工具,擴展接口爲 Serialization, ObjectInput, ObjectOutput, ThreadPool

這裏引用一張肥朝博客的總結圖,來總結服務暴露所幹的事情:
首先是經過動態代理店的方式將暴露的接口組裝成url形式的invoker,而後再根據url的配置信息來指定傳輸協議、交換方式、序列化方式等等,因爲dubbo採用了自定義的SPI擴展,各層之間都是相互獨立的,只有在調用的時候才知道所調用的具體擴展實現,這裏仍是以jdk或者javasisit的方式來動態代理實現。

 
服務暴露流程

2.4 服務引用

首先 ReferenceConfig 類的init方法調用 Protocol 的 refer方法生成 Invoker 實例(如上圖中的紅色部分),這是服務消費的關鍵。接下來把 Invoker 轉換爲客戶端須要的接口(如:HelloWorld)。關於每種協議如 RMI/Dubbo/Web service 等它們在調用 refer 方法生成Invoker 實例的細節和上一章節所描述的相似。

 
服務應用流程

上述圖和文字是摘自官方文檔的原話(地址在這裏),總結來講就是幹了兩件事情:一、將spring的schemas標籤信息轉換bean,而後經過這個bean的信息,鏈接、訂閱zookeeper節點信息建立一個invoker。二、將invoker的信息建立一個動態代理對象。貼一張服務應用的時序圖:

 
服務引用時序

這裏又一次出現了Invoker,這個抽象的概念真是無處不在呀,dubbo中最重要的兩種 Invoker:服務提供 Invoker 和服務消費 InvokerInvoker從類的設計信息上是封裝了 Provider和Consumer地址及 Service 接口信息,咱們在本身的子系統調用遠程接口的時候,會像調用本身的方法同樣,好比在消費端這裏用註解@Autowirted自動注入一個遠程接口進來,這個遠程接口就是上圖中服務消費端的 proxy,可是遠程接口是須要網絡通訊、編碼解碼等等一系列工做的,要封裝這個通訊細節,讓用戶像以本地調用方式調用遠程服務,就必須使用代理,而後說到動態代理,用戶代碼經過這個 proxy 調用其對應的 Invoker ,而該 Invoker 實現了真正的遠程服務調用。

 
image.png

3、Dubbo實戰應用

實戰應用主要是從應用層面講引入dubbo框架後如何作一些關鍵配置

3.1 Dubbo 支持四種配置方式:

XML 配置:基於 Spring 的 Schema 和 XML 擴展機制實現(推薦)
屬性配置:加載 classpath 根目錄下的 dubbo.properties
API 配置:經過硬編碼方式配置(不推薦使用,可學習加深源碼理解)
註解配置:經過註解方式配置(Dubbo-2.5.7及以上版本支持,不推薦使用)

3.2 集羣容錯

在集羣調用失敗時,Dubbo 提供了多種容錯方案,缺省爲 failover 重試。

 
集羣容錯
  • Invoker 是 Provider 的一個可調用 Service 的抽象,Invoker 封裝了 Provider 地址及 Service 接口信息
  • Directory 表明多個 Invoker,能夠把它當作 List<Invoker> ,但與 List 不一樣的是,它的值多是動態變化的,好比註冊中心推送變動
  • Cluster 將 Directory 中的多個 Invoker 假裝成一個 Invoker,對上層透明,假裝過程包含了容錯邏輯,調用失敗後,重試另外一個
  • Router 負責從多個 Invoker 中按路由規則選出子集,好比讀寫分離,應用隔離等
  • LoadBalance 負責從多個 Invoker 中選出具體的一個用於本次調用,選的過程包含了負載均衡算法,調用失敗後,須要重選。

集羣調用的配置可從以下列表中選擇:

<dubbo:service cluster="failsafe" /> <!-- 或者 --> <dubbo:reference cluster="failsafe" /> 
集羣模式 說明
Failfast Cluster 快速失敗,只發起一次調用,失敗當即報錯。一般用於非冪等性的寫操做,好比新增記錄。
Failsafe Cluster 失敗安全,出現異常時,直接忽略。一般用於寫入審計日誌等操做。
Failback Cluster 失敗自動恢復,後臺記錄失敗請求,定時重發。一般用於消息通知操做。
Forking Cluster 並行調用多個服務器,只要一個成功即返回。一般用於實時性要求較高的讀操做,但須要浪費更多服務資源。可經過 forks="2" 來設置最大並行數。
Broadcast Cluster 廣播調用全部提供者,逐個調用,任意一臺報錯則報錯 [2]。一般用於通知全部提供者更新緩存或日誌等本地資源信息。

3.3 負載均衡

Random LoadBalance

  • 隨機,按權重設置隨機機率。
  • 在一個截面上碰撞的機率高,但調用量越大分佈越均勻,並且按機率使用權重後也比較均勻,有利於動態調整提供者權重。

RoundRobin LoadBalance

  • 輪詢,按公約後的權重設置輪詢比率。
  • 存在慢的提供者累積請求的問題,好比:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,長此以往,全部請求都卡在調到第二臺上。

LeastActive LoadBalance

  • 最少活躍調用數,相同活躍數的隨機,活躍數指調用先後計數差。
  • 使慢的提供者收到更少請求,由於越慢的提供者的調用先後計數差會越大。

ConsistentHash LoadBalance

  • 一致性 Hash,相同參數的請求老是發到同一提供者。
  • 當某一臺提供者掛時,本來發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引發劇烈變更。
  • 算法參見:http://en.wikipedia.org/wiki/Consistent_hashing
  • 缺省只對第一個參數 Hash,若是要修改,請配置 <dubbo:parameter key="hash.arguments" value="0,1" />
  • 缺省用 160 份虛擬節點,若是要修改,請配置 <dubbo:parameter key="hash.nodes" value="320" />
、dubbo面談<!--服務端服務級別--> <dubbo:service interface="..." loadbalance="roundrobin" /> <!--客戶端服務級別--> <dubbo:reference interface="..." loadbalance="roundrobin" /> <!--服務端方法級別--> <dubbo:service interface="..."> <dubbo:method name="..." loadbalance="roundrobin"/> </dubbo:service> <!--客戶端方法級別--> <dubbo:reference interface="..."> <dubbo:method name="..." loadbalance="roundrobin"/> </dubbo:reference>

SPI

一、你是否瞭解SPI,講一講什麼是SPI,爲何要使用SPI?
SPI具體約定:當服務的提供者,提供了服務接口的一種實現以後,在jar包的META-INF/services/目錄裏同時建立一個以服務接口命名的文件。該文件裏就是實現該服務接口的具體實現類。而當外部程序裝配這個模塊的時候,就能經過該jar包META-INF/services/裏的配置文件找到具體的實現類名,並裝載實例化,完成模塊的注入(從使用層面來講,就是運行時,動態給接口添加實現類)。 基於這樣一個約定就能很好的找到服務接口的實現類,而不須要再代碼裏制定(不須要在代碼裏寫死)。

這樣作的好處:java設計出SPI目的是爲了實如今模塊裝配的時候能不在程序裏動態指明,這就須要一種服務發現機制。這樣程序運行的時候,該機制就會爲某個接口尋找服務的實現,有點相似IOC的思想,就是將裝配的控制權移到程序以外,在模塊化設計中這個機制尤爲重要。例如,JDBC驅動,能夠加載MySQL、Oracle、或者SQL Server等,目前有很多框架用它來作服務的擴張發現。回答這個問題能夠延伸一下和API的對比,API是將方法封裝起來給調用者使用的,SPI是給擴展者使用的。

二、對類加載機制瞭解嗎,說一下什麼是雙親委託模式,他有什麼弊端,這個弊端有沒有什麼咱們熟悉的案例,解決這個弊端的原理又是怎麼樣的?
擴展延生的一道題。

三、Dubbo的SPI和JDK的SPI有區別嗎?有的話,究竟有什麼區別?
Dubbo 的擴展點加載是基於JDK 標準的 SPI 擴展點發現機制加強而來的,Dubbo 改進了 JDK 標準的 SPI 的如下問題:

  • JDK 標準的 SPI 會一次性實例化擴展點全部實現,若是有擴展實現初始化很耗時,但若是沒用上也加載,會很浪費資源。
  • 增長了對擴展點 IoC 和 AOP 的支持,一個擴展點能夠直接 setter 注入其它擴展點。

上文已提供。另外在博客中也單獨對此寫了一篇《Dubbo內核之SPI機制》《跟我學Dubbo系列之Java SPI機制簡介》

四、Dubbo中SPI也增長了IoC,先講講Spring的IoC,而後再講講Dubbo裏面又是怎麼作的
五、Dubbo中SPI也增長了AOP,那你講講這用到了什麼設計模式,Dubbo又是如何作的.

Dubbo原理

一、Dubbo角色和設計是怎麼樣的,原理是怎麼樣的?請簡單談談?

 
Dubbo角色和設計

 

二、有沒有考慮過本身實現一個相似dubbo的RPC框架,若是有,請問你會若是着手實現?(面試高頻題,區分度高)
可從兩個方面去入手,考慮接口擴展性,改造JDK的SPI機制來實現本身的擴展SPI機制。另外就是從動態代理入手,從網絡通訊、編碼解碼這些步驟以動態代理的方式植入遠程調用方法中,實現透明化的調用。

三、用過mybatis是否知道Mapper接口的原理嗎?(若是回答得不錯,而且提到動態代理這個關鍵詞會繼續往下問,那這個動態代理又是如何經過依賴注入到Mapper接口的呢?)

四、服務發佈過程當中作了哪些事?
暴露本地服務、暴露遠程服務、啓動netty、鏈接zookeeper、到zookeeper註冊、監聽zookeeper

五、dubbo都有哪些協議,他們之間有什麼特色,缺省值是什麼?
dubbo支持多種協議,默認使用的是dubbo協議,具體介紹官方文檔寫得很清楚,傳送地址:相關協議介紹,重點是掌握好推薦dubbo協議。Dubbo 缺省協議採用單一長鏈接和 NIO 異步通信,適合於小數據量大併發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的狀況。

六、什麼是本地暴露和遠程暴露,他們的區別?
在dubbo中咱們一個服務可能既是Provider,又是Consumer,所以就存在他本身調用本身服務的狀況,若是再經過網絡去訪問,那天然是捨近求遠,所以他是有本地暴露服務的這個設計.從這裏咱們就知道這個二者的區別

  • 本地暴露是暴露在JVM中,不須要網絡通訊.
  • 遠程暴露是將ip,端口等信息暴露給遠程客戶端,調用時須要網絡通訊.

七、服務暴露中遠程暴露的整體過程,畫圖和文字方式說明
詳見上述說明

zookeeper

一、通常選擇什麼註冊中心,還有別的選擇嗎?
zk爲默認推薦,其他還有Multicast、redis、Simple等註冊中心。

二、dubbo中zookeeper作註冊中心,若是註冊中心集羣都掛掉,那發佈者和訂閱者還能通訊嗎?(面試高頻題)
zookeeper的信息會緩存到服務器本地做爲一個cache緩存文件,而且轉換成properties對象方便使用,每次調用時,按照本地存儲的地址進行調用,可是沒法從註冊中心去同步最新的服務列表,短時間的註冊中心掛掉是沒關係的,但必定要儘快修復。因此掛掉是沒關係的,但前提是你沒有增長新的服務,若是你要調用新的服務,則是不能辦到的。

三、項目中有使用過多線程嗎?有的話講講你在哪裏用到了多線程?(面試高頻題)
以dubbo爲例,這裏的作法是:創建線程池,定時的檢測並鏈接註冊中心,若是失敗了就重連,其實也就是一個定時任務執行器。可能作了兩三年java還沒真正在項目中開啓過線程,問到這個問題時菊花一緊,可是定時任務執行器這種需求在項目中仍是很常見的,好比失敗重連、輪詢執行任務等等,能夠參考這個例子,把大家的定時任務場景和這裏的多線程用法套在一塊兒。

 
dubbo檢測zk連接

 

四、zookeeper的java客戶端你使用過哪些?
zookeeper是支持ZkClient和Curator兩種,關於zk的使用場景,除了以dubbo做爲註冊中心之外,zk在分佈式環境做爲協調服務器有許多應用場景,能夠嘗試用java來調用zk服務作一些協調服務,如負載均衡、數據訂閱與發佈等等。SnailClimb寫了一篇優秀的博客《多是全網把ZK概念講的最清楚的一篇文章》

 
zookeeper知識點一覽圖

 

五、服務提供者能實現失效踢出是什麼原理(高頻題)
在分佈式系統中,咱們經常須要知道某個機器是否可用,傳統的開發中,能夠經過Ping某個主機來實現,Ping得通說明對方是可用的,相反是不可用的,ZK 中咱們讓全部的機器都註冊一個臨時節點,咱們判斷一個機器是否可用,咱們只須要判斷這個節點在ZK中是否存在就能夠了,不須要直接去鏈接須要檢查的機器,下降系統的複雜度。

六、zookeeper的有哪些節點,他們有什麼區別?講一下應用場景
zookeeper中節點是有生命週期的.具體的生命週期取決於節點的類型.節點主要分爲持久節點(Persistent)和臨時節點(Ephemeral),可是更詳細的話還能夠加上時序節點(Sequential),建立節點中每每組合使用,所以也就是4種:持久節點、持久順序節點、臨時節點、臨時順序節點。

  • 所謂持久節點,是指在節點建立後,就一直存在,直到有刪除操做來主動清除這個節點,也就是說不會由於建立該節點的客戶端會話失效而消失。
  • 臨時節點的生命週期和客戶端會話綁定,也就是說,若是客戶端會話失效,那麼這個節點就會自動被清除掉。

七、在dubbo中,何時更新本地的zookeeper信息緩存文件?訂閱zookeeper信息的總體過程是怎麼樣的?
dubbo向zk發送了訂閱請求之後,會去監聽zk的回調,(若是zk有回調就回去調用notify方法),接着會去建立接口配置信息的持久化節點,同時dubbo也設置了對該節點的監聽,zk節點若是發生了變化那麼會觸發回調方法,去更新zk信息的緩存文件,同時註冊服務在調用的時候會去對比最新的配置信息節點,有差異的話會以最新信息爲準從新暴露。《dubbo源碼解析-zookeeper訂閱》

 
zk訂閱流程

服務引用
一、描述一下dubbo服務引用的過程,原理
上文已提供。

二、既然你提到了dubbo的服務引用中封裝通訊細節是用到了動態代理,那請問建立動態代理經常使用的方式有哪些,他們又有什麼區別?dubbo中用的是哪種?(高頻題)
jdk、cglib還有javasisit,JDK的動態代理代理的對象必需要實現一個接口,而針對於沒有接口的類,則可用CGLIB。要明白二者區別必需要了解原理,明白了原理天然一通百通,CGLIB其原理也很簡單,對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但因爲採用的是繼承,因此不能對final修飾的類進行代理。除了以上兩種你們都很熟悉的方式外,其實還有一種方式,就是javassist生成字節碼來實現代理(dubbo多處用到了javassist)。

集羣容錯
一、dubbo提供了集中集羣容錯模式?
二、談談dubbo中的負載均衡算法及特色?最小活躍數算法中是如何統計活躍數的?簡單談談一致性哈希算法
這部分能夠多結合官方文檔進行學習,並且涉及到了負載均衡的多個重要算法,也是高頻的考察熱點。

三、怎麼經過dubbo實現服務降級的,降級的方式有哪些,又有什麼區別?
當網站處於高峯期時,併發量大,服務能力有限,那麼咱們只能暫時屏蔽邊緣業務,這裏面就要採用服務降級策略了。首先dubbo中的服務降級分紅兩個:屏蔽(mock=force)、容錯(mock=fail)。

  • mock=force:return+null 表示消費方對該服務的方法調用都直接返回 null 值,不發起遠程調用。用來屏蔽不重要服務不可用時對調用方的影響。
  • mock=fail:return+null 表示消費方對該服務的方法調用在失敗後,再返回 null 值,不拋異常。用來容忍不重要服務不穩定時對調用方的影響。

要生效須要在dubbo後臺進行配置的修改:


 
服務降級策略

四、dubbo監控平臺可以動態改變接口的一些設置,其原理是怎樣的? 改變註冊在zookeeper上的節點信息,從而zookeeper通知從新生成invoker(這些具體細節在zookeeper建立節點,zookeeper鏈接,zookeeper訂閱中都詳細講了,這裏再也不重複)。

相關文章
相關標籤/搜索