天天看點

探究Dubbo的ExtensionLoader

一、Dubbo是什麼

Dubbo 是一個分布式、高性能、透明化的 RPC 服務架構,提供服務自動注冊、自動發現等高效服務治理方案, 可以和 Spring 架構無縫內建。

RPC 指的是遠端調用協定,也就是說兩個伺服器互動資料。

二、Dubbo的由來

1、背景

網際網路的快速發展,Web應用程式的規模不斷擴大,一般會經曆如下四個發展階段。

單一應用架構

探究Dubbo的ExtensionLoader

當網站流量很小時,隻需一個應用,将所有功能都部署在一起,以減少部署節點和成本。

此時,用于簡化增删改查工作量的 資料通路架構(ORM) 是關鍵。

垂直應用架構

探究Dubbo的ExtensionLoader

當通路量逐漸增大,單一應用增加機器帶來的加速度越來越小,将應用拆成互不相幹的幾個應用,以提升效率。

此時,用于加速前端頁面開發的 Web架構(MVC) 是關鍵。

分布式服務架構

探究Dubbo的ExtensionLoader

當垂直應用越來越多,應用之間互動不可避免,将核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。

此時,用于提高業務複用及整合的 分布式服務架構(RPC) 是關鍵。

流動計算架構

探究Dubbo的ExtensionLoader

當服務越來越多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增加一個排程中心基于通路壓力實時管理叢集容量,提高叢集使用率。

此時,用于提高機器使用率的 資源排程和治理中心(SOA) 是關鍵。

2、需求

探究Dubbo的ExtensionLoader

在大規模服務化之前,應用可能隻是通過RMI或Hessian等工具,簡單的暴露和引用遠端服務,通過配置服務的URL位址進行調用,通過F5等硬體進行負載均衡。

  • (1) 當服務越來越多時,服務URL配置管理變得非常困難,F5硬體負載均衡器的單點壓力也越來越大。

    此時需要一個服務注冊中心,動态的注冊和發現服務,使服務的位置透明。

    并通過在消費方擷取服務提供方位址清單,實作軟負載均衡和Failover,降低對F5硬體負載均衡器的依賴,也能減少部分成本。

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

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

  • (3) 接着,服務的調用量越來越大,服務的容量問題就暴露出來,這個服務需要多少機器支撐?什麼時候該加機器?

    為了解決這些問題,第一步,要将服務現在每天的調用量,響應時間,都統計出來,作為容量規劃的參考名額。

    其次,要可以動态調整權重,線上上,将某台機器的權重一直加大,并在加大的過程中記錄響應時間的變化,直到響應時間到達閥值,記錄此時的通路量,再以此通路量乘以機器數反推總容量。

    以上是Dubbo最基本的幾個需求,更多服務治理問題參見:

    http://code.alibabatech.com/blog/experience_1402/service-governance-process.html

3.Dubbo的主要應用場景?

透明化的遠端方法調用,就像調用本地方法一樣調用遠端方法,隻需簡單配置,沒有任何API侵入。

軟負載均衡及容錯機制,可在内網替代F5等硬體負載均衡器,降低成本,減少單點。

服務自動注冊與發現,不再需要寫死服務提供方位址,注冊中心基于接口名查詢服務提供者的IP位址,并且能夠平滑添加或删除服務提供者。

4.Dubbo的核心功能?

主要就是如下3個核心功能:

  • **Remoting:**網絡通信架構,提供對多種NIO架構抽象封裝,包括“同步轉異步”和“請求-響應”模式的資訊交換方式。
  • Cluster:服務架構,提供基于接口方法的透明遠端過程調用,包括多協定支援,以及軟負載均衡,失敗容錯,位址路由,動态配置等叢集支援。
  • Registry:服務注冊,基于注冊中心目錄服務,使服務消費方能動态的查找服務提供方,使位址透明,使服務提供方可以平滑增加或減少機器。

5.Dubbo的核心元件?

探究Dubbo的ExtensionLoader

6.Dubbo服務注冊與發現的流程?

探究Dubbo的ExtensionLoader

節點角色說明:

  • Provider: 暴露服務的服務提供方。
  • Consumer: 調用遠端服務的服務消費方。
  • Registry: 服務注冊與發現的注冊中心。
  • Monitor: 統計服務的調用次調和調用時間的監控中心。
  • Container: 服務運作容器。

調用關系說明:

  • 0.服務容器負責啟動,加載,運作服務提供者。
  • 1.服務提供者在啟動時,向注冊中心注冊自己提供的服務。
  • 2.服務消費者在啟動時,向注冊中心訂閱自己所需的服務。
  • 3.注冊中心傳回服務提供者位址清單給消費者,如果有變更,注冊中心将基于長連接配接推送變更資料給消費者。
  • 4.服務消費者,從提供者位址清單中,基于軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。
  • 5.服務消費者和提供者,在記憶體中累計調用次數和調用時間,定時每分鐘發送一次統計資料到監控中心。

流程說明:

  • Provider(提供者)綁定指定端口并啟動服務
  • 指供者連接配接注冊中心,将本機IP、端口、應用資訊和提供服務資訊發送至注冊中心存儲
  • Consumer(消費者),連接配接注冊中心 ,并發送應用資訊、所求服務資訊至注冊中心
  • 注冊中心根據 消費 者所求服務資訊比對對應的提供者清單發送至Consumer 應用緩存。
  • Consumer 在發起遠端調用時基于緩存的消費者清單擇其一發起調用。
  • Provider 狀态變更會實時通知注冊中心、在由注冊中心實時推送至Consumer

設計的原因:

  • Consumer 與Provider 解偶,雙方都可以橫向增減節點數。
  • 注冊中心對本身可做對等叢集,可動态增減節點,并且任意一台宕掉後,将自動切換到另一台
  • 去中心化,雙方不直接依懶注冊中心,即使注冊中心全部當機短時間内也不會影響服務的調用
  • 服務提供者無狀态,任意一台宕掉後,不影響使用
探究Dubbo的ExtensionLoader

7.Dubbo的架構設計?

探究Dubbo的ExtensionLoader

Dubbo架構設計一共劃分了10個層:

Dubbo架構設計一共劃分了10個層,而最上面的Service層是留給實際想要使用Dubbo開發分布式服務的開發者實作業務邏輯的接口層。圖中左邊淡藍背景的為服務消費方使用的接口,右邊淡綠色背景的為服務提供方使用的接口, 位于中軸線上的為雙方都用到的接口。

下面,結合Dubbo官方文檔,我們分别了解一下架構分層架構中,各個層次的設計要點:

  • 服務接口層(Service):該層是與實際業務邏輯相關的,根據服務提供方和服務消費方的業務設計對應的接口和實作。
  • 配置層(Config):對外配置接口,以ServiceConfig和ReferenceConfig為中心,可以直接new配置類,也可以通過spring解析配置生成配置類。
  • 服務代理層(Proxy):服務接口透明代理,生成服務的用戶端Stub和伺服器端Skeleton,以ServiceProxy為中心,擴充接口為ProxyFactory。
  • 服務注冊層(Registry):封裝服務位址的注冊與發現,以服務URL為中心,擴充接口為RegistryFactory、Registry和RegistryService。可能沒有服務注冊中心,此時服務提供方直接暴露服務。
  • 叢集層(Cluster):封裝多個提供者的路由及負載均衡,并橋接注冊中心,以Invoker為中心,擴充接口為Cluster、Directory、Router和LoadBalance。将多個服務提供方組合為一個服務提供方,實作對服務消費方來透明,隻需要與一個服務提供方進行互動。
  • 監控層(Monitor):RPC調用次數和調用時間監控,以Statistics為中心,擴充接口為MonitorFactory、Monitor和MonitorService。
  • 遠端調用層(Protocol):封将RPC調用,以Invocation和Result為中心,擴充接口為Protocol、Invoker和Exporter。Protocol是服務域,它是Invoker暴露和引用的主功能入口,它負責Invoker的生命周期管理。Invoker是實體域,它是Dubbo的核心模型,其它模型都向它靠擾,或轉換成它,它代表一個可執行體,可向它發起invoke調用,它有可能是一個本地的實作,也可能是一個遠端的實作,也可能一個叢集實作。
  • 資訊交換層(Exchange):封裝請求響應模式,同步轉異步,以Request和Response為中心,擴充接口為Exchanger、ExchangeChannel、ExchangeClient和ExchangeServer。
  • 網絡傳輸層(Transport):抽象mina和netty為統一接口,以Message為中心,擴充接口為Channel、Transporter、Client、Server和Codec。
  • 資料序列化層(Serialize):可複用的一些工具,擴充接口為Serialization、 ObjectInput、ObjectOutput和ThreadPool。

從上圖可以看出,Dubbo對于服務提供方和服務消費方,從架構的10層中分别提供了各自需要關心和擴充的接口,建構整個服務生态系統(服務提供方和服務消費方本身就是一個以服務為中心的)。

根據官方提供的,對于上述各層之間關系的描述,如下所示:

在RPC中,Protocol是核心層,也就是隻要有Protocol + Invoker + Exporter就可以完成非透明的RPC調用,然後在Invoker的主過程上Filter攔截點。

圖中的Consumer和Provider是抽象概念,隻是想讓看圖者更直覺的了解哪些類分屬于用戶端與伺服器端,不用Client和Server的原因是Dubbo在很多場景下都使用Provider、Consumer、Registry、Monitor劃分邏輯拓普節點,保持統一概念。

而Cluster是外圍概念,是以Cluster的目的是将多個Invoker僞裝成一個Invoker,這樣其它人隻要關注Protocol層Invoker即可,加上Cluster或者去掉Cluster對其它層都不會造成影響,因為隻有一個提供者時,是不需要Cluster的。

Proxy層封裝了所有接口的透明化代理,而在其它層都以Invoker為中心,隻有到了暴露給使用者使用時,才用Proxy将Invoker轉成接口,或将接口實作轉成Invoker,也就是去掉Proxy層RPC是可以Run的,隻是不那麼透明,不那麼看起來像調本地服務一樣調遠端服務。

而Remoting實作是Dubbo協定的實作,如果你選擇RMI協定,整個Remoting都不會用上,Remoting内部再劃為Transport傳輸層和Exchange資訊交換層,Transport層隻負責單向消息傳輸,是對Mina、Netty、Grizzly的抽象,它也可以擴充UDP傳輸,而Exchange層是在傳輸層之上封裝了Request-Response語義。

Registry和Monitor實際上不算一層,而是一個獨立的節點,隻是為了全局概覽,用層的方式畫在一起。

8.設計的優勢

(1) 連通性:

  • 注冊中心負責服務位址的注冊與查找,相當于目錄服務,服務提供者和消費者隻在啟動時與注冊中心互動,注冊中心不轉發請求,壓力較小
  • 監控中心負責統計各服務調用次數,調用時間等,統計先在記憶體彙總後每分鐘一次發送到監控中心伺服器,并以報表展示
  • 服務提供者向注冊中心注冊其提供的服務,并彙報調用時間到監控中心,此時間不包含網絡開銷
  • 服務消費者向注冊中心擷取服務提供者位址清單,并根據負載算法直接調用提供者,同時彙報調用時間到監控中心,此時間包含網絡開銷
  • 注冊中心,服務提供者,服務消費者三者之間均為長連接配接,監控中心除外
  • 注冊中心通過長連接配接感覺服務提供者的存在,服務提供者當機,注冊中心将立即推送事件通知消費者
  • 注冊中心和監控中心全部當機,不影響已運作的提供者和消費者,消費者在本地緩存了提供者清單
  • 注冊中心和監控中心都是可選的,服務消費者可以直連服務提供者

(2) 健狀性:

  • 監控中心宕掉不影響使用,隻是丢失部分采樣資料
  • 資料庫宕掉後,注冊中心仍能通過緩存提供服務清單查詢,但不能注冊新服務
  • 注冊中心對等叢集,任意一台宕掉後,将自動切換到另一台
  • 注冊中心全部宕掉後,服務提供者和服務消費者仍能通過本地緩存通訊
  • 服務提供者無狀态,任意一台宕掉後,不影響使用
  • 服務提供者全部宕掉後,服務消費者應用将無法使用,并無限次重連等待服務提供者恢複

(3) 伸縮性:

  • 注冊中心為對等叢集,可動态增加機器部署執行個體,所有用戶端将自動發現新的注冊中心
  • 服務提供者無狀态,可動态增加機器部署執行個體,注冊中心将推送新的服務提供者資訊給消費者

(4) 更新性:

  • 當服務叢集規模進一步擴大,帶動IT治理結構進一步更新,需要實作動态部署,進行流動計算,現有分布式服務架構不會帶來阻力:
探究Dubbo的ExtensionLoader

9.Dubbo的服務調用流程?

探究Dubbo的ExtensionLoader

10.Dubbo支援哪些協定,每種協定的應用場景,優缺點?

  • dubbo: 單一長連接配接和NIO異步通訊,适合大并發小資料量的服務調用,以及消費者遠大于提供者。傳輸協定TCP,異步,Hessian序列化;
  • rmi: 采用JDK标準的rmi協定實作,傳輸參數和傳回參數對象需要實作Serializable接口,使用java标準序列化機制,使用阻塞式短連接配接,傳輸資料包大小混合,消費者和提供者個數差不多,可傳檔案,傳輸協定TCP。

    多個短連接配接,TCP協定傳輸,同步傳輸,适用正常的遠端服務調用和rmi互操作。在依賴低版本的Common-Collections包,java序列化存在安全漏洞;

  • webservice: 基于WebService的遠端調用協定,內建CXF實作,提供和原生WebService的互操作。多個短連接配接,基于HTTP傳輸,同步傳輸,适用系統內建和跨語言調用;
  • http: 基于Http表單送出的遠端調用協定,使用Spring的HttpInvoke實作。多個短連接配接,傳輸協定HTTP,傳入參數大小混合,提供者個數多于消費者,需要給應用程式和浏覽器JS調用;
  • hessian: 內建Hessian服務,基于HTTP通訊,采用Servlet暴露服務,Dubbo内嵌Jetty作為伺服器時預設實作,提供與Hession服務互操作。多個短連接配接,同步HTTP傳輸,Hessian序列化,傳入參數較大,提供者大于消費者,提供者壓力較大,可傳檔案;
  • memcache: 基于memcached實作的RPC協定
  • redis: 基于redis實作的RPC協定

11.dubbo推薦用什麼協定?

預設使用dubbo協定

12.Dubbo有些哪些注冊中心?

  • Multicast注冊中心: Multicast注冊中心不需要任何中心節點,隻要廣播位址,就能進行服務注冊和發現。基于網絡中多點傳播傳輸實作;
  • Zookeeper注冊中心: 基于分布式協調系統Zookeeper實作,采用Zookeeper的watch機制實作資料變更;
  • redis注冊中心: 基于redis實作,采用key/Map存儲,住key存儲服務名和類型,Map中key存儲服務URL,value服務過期時間。基于redis的釋出/訂閱模式通知資料變更;
  • Simple注冊中心

13.Dubbo的服務治理?

探究Dubbo的ExtensionLoader
  • 過多的服務URL配置困難
  • 負載均衡配置設定節點壓力過大的情況下也需要部署叢集
  • 服務依賴混亂,啟動順序不清晰
  • 過多服務導緻性能名額分析難度較大,需要監控

14.Dubbo的注冊中心叢集挂掉,釋出者和訂閱者之間還能通信麼?

可以的,啟動dubbo時,消費者會從zookeeper拉取注冊的生産者的位址接口等資料,緩存在本地。

每次調用時,按照本地存儲的位址進行調用。

15.Dubbo與Spring的關系?

Dubbo采用全Spring配置方式,透明化接入應用,對應用沒有任何API侵入,隻需用Spring加載Dubbo的配置即可,Dubbo基于Spring的Schema擴充進行加載。

16.Dubbo使用的是什麼通信架構?

預設使用NIO Netty架構

17.Dubbo叢集提供了哪些負載均衡政策?

  • Random LoadBalance: 随機選取提供者政策,有利于動态調整提供者權重。截面碰撞率高,調用次數越多,分布越均勻;
  • RoundRobin LoadBalance: 輪循選取提供者政策,平均分布,但是存在請求累積的問題;
  • LeastActive LoadBalance: 最少活躍調用政策,解決慢提供者接收更少的請求;
  • ConstantHash LoadBalance: 一緻性Hash政策,使相同參數請求總是發到同一提供者,一台機器當機,可以基于虛拟節點,分攤至其他提供者,避免引起提供者的劇烈變動;

預設時為Random随機調用

18.Dubbo的叢集容錯方案有哪些?

  • Failover Cluster
  • 失敗自動切換,當出現失敗,重試其它伺服器。通常用于讀操作,但重試會帶來更長延遲。
  • Failfast Cluster
  • 快速失敗,隻發起一次調用,失敗立即報錯。通常用于非幂等性的寫操作,比如新增記錄。
  • Failsafe Cluster
  • 失敗安全,出現異常時,直接忽略。通常用于寫入審計日志等操作。
  • Failback Cluster
  • 失敗自動恢複,背景記錄失敗請求,定時重發。通常用于消息通知操作。
  • Forking Cluster
  • 并行調用多個伺服器,隻要一個成功即傳回。通常用于實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks=”2″ 來設定最大并行數。
  • Broadcast Cluster
  • 廣播調用所有提供者,逐個調用,任意一台報錯則報錯 。通常用于通知所有提供者更新緩存或日志等本地資源資訊。

更多Dubbo叢集容錯配置請參考:

Dubbo學習筆記7:Dubbo的叢集容錯與負載均衡政策

Dubbo學習源碼總結系列四--叢集容錯機制

Dubbo叢集容錯方案

19.Dubbo的預設叢集容錯方案?

  • Failover Cluster
  • retries重試次數為2次,不包括第一次

SpringBoot配置為:

#dubbo叢集容錯6種方案failover,failfast,failsafe,failback,forking,froadcast,
#預設為failover 預設重試次數為2次
spring.dubbo.reference.cluster=failover
spring.dubbo.reference.retries=2
           

Dubbo服務配置的優先級别

用戶端的配置優先于服務端

  • 1、方法級别優先,然後是接口,最後是全局配置
  • 2、如果級别是一樣的,用戶端優先

    retries(用戶端)、LoadBalance(用戶端)、cluster(用戶端)、timeout(服務端)

Dubbo服務降級

降級的目的是為了保證核心服務可用

dubbo的降級方式:mock

本地僞裝通常用于服務降級,比如某驗權服務,當服務提供方全部挂掉後,用戶端不抛出異常,而是通過 Mock 資料傳回授權失敗。

在 spring 配置檔案中按以下方式配置:

<dubbo:reference interface="com.foo.BarService" mock="true" />

           

<dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />

           

在工程中提供 Mock 實作:

package com.foo;
public class BarServiceMock implements BarService {
    public String sayHello(String name) {
        // 你可以僞造容錯資料,此方法隻在出現RpcException時被執行
        return "容錯資料";
    }
}

           

如果服務的消費方經常需要 try-catch 捕獲異常,如:

Offer offer = null;
try {
    offer = offerService.findOffer(offerId);
} catch (RpcException e) {
   logger.error(e);
}

           

請考慮改為 Mock 實作,并在 Mock 實作中 return null。如果隻是想簡單的忽略異常,在 

2.0.11

 以上版本可用:

<dubbo:reference interface="com.foo.BarService" mock="return null" />
           

更多Dubbo降級用法請參考Dubbo官方文檔:

http://dubbo.apache.org/zh-cn/docs/user/demos/local-mock.html

Dubbo的SPI機制

Dubbo 的擴充點加載從 JDK 标準的 SPI (Service Provider Interface) 擴充點發現機制加強而來。

Dubbo 改進了 JDK 标準的 SPI 的以下問題:

  • JDK标準的 SPI 會一次性執行個體化擴充點所有實作,如果有擴充實作初始化很耗時,但如果沒用上也加載,會很浪費資源。
  • 如果擴充點加載失敗,連擴充點的名稱都拿不到了。比如:JDK 标準的 ScriptEngine,通過 getName() 擷取腳本類型的名稱,但如果 RubyScriptEngine 因為所依賴的 jruby.jar 不存在,導緻 RubyScriptEngine 類加載失敗,這個失敗原因被吃掉了,和 ruby 對應不起來,當使用者執行 ruby 腳本時,會報不支援 ruby,而不是真正失敗的原因。
  • 增加了對擴充點 IoC 和 AOP 的支援,一個擴充點可以直接 setter 注入其它擴充點。

SPI接口定義

定義了@SPI注解

public @interface SPI {

  String value() default ""; //指定預設的擴充點

} 
           

隻有在接口打了@SPI注解的接口類才會去查找擴充點實作

會依次從這幾個檔案中讀取擴充點

META-INF/dubbo/internal/   //dubbo内部實作的各種擴充都放在了這個目錄了

META-INF/dubbo/

META-INF/services/
           

在擴充類的 jar 包内,放置擴充點配置檔案 META-INF/dubbo/接口全限定名,内容為:配置名=擴充實作類全限定名,多個實作類用換行符分隔。

以擴充 Dubbo 的協定為例,在協定的實作 jar 包内放置文本檔案:META-INF/dubbo/org.apache.dubbo.rpc.Protocol,内容為:

xxx=com.alibaba.xxx.XxxProtocol
           

更多關于Dubbo的SPI機制請閱讀:

http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html

2. Dubbo原了解析-Dubbo核心實作之基于SPI思想Dubbo核心實作(轉)

Dubbo的SPI機制

聊聊Dubbo(五):核心源碼-SPI擴充

20.Dubbo支援哪些序列化方式?

預設使用Hessian序列化,還有Dubbo、FastJson、Java自帶序列化。

21.Dubbo逾時時間怎樣設定?

Dubbo逾時時間設定有兩種方式:

  • 服務提供者端設定逾時時間,在Dubbo的使用者文檔中,推薦如果能在服務端多配置就盡量多配置,因為服務提供者比消費者更清楚自己提供的服務特性。
  • 服務消費者端設定逾時時間,如果在消費者端設定了逾時時間,以消費者端為主,即優先級更高。因為服務調用方設定逾時時間控制性更靈活。如果消費方逾時,服務端線程不會定制,會産生警告。

22.服務調用逾時問題怎麼解決?

dubbo在調用服務不成功時,預設是會重試兩次的。

23.Dubbo在安全機制方面是如何解決?

Dubbo通過Token令牌防止使用者繞過注冊中心直連,然後在注冊中心上管理授權。Dubbo還提供服務黑白名單,來控制服務所允許的調用方。

24.dubbo 和 dubbox 之間的差別?

dubbox 基于 dubbo 上做了一些擴充,如加了服務可 restful 調用,更新了開源元件等。

25.除了Dubbo還有哪些分布式架構?

大家熟知的就是Spring cloud,當然國外也有類似的多個架構。

26.Dubbo和Spring Cloud的關系?

  • Dubbo

    是 SOA 時代的産物,它的關注點主要在于服務的調用,流量分發、流量監控和熔斷。

  • Spring Cloud

    誕生于微服務架構時代,考慮的是微服務治理的方方面面,另外由于依托了Spring、Spirng Boot的優勢之上,兩個架構在開始目标就不一緻,Dubbo 定位服務治理、Spirng Cloud 是一個生态。

27.dubbo和spring cloud的差別?

最大的差別:Dubbo底層是使用Netty這樣的NIO架構,是基于TCP協定傳輸的,配合以Hession序列化完成RPC通信。

而SpringCloud是基于Http協定+Rest接口調用遠端過程的通信,相對來說,Http請求會有更大的封包,占的帶寬也會更多。但是REST相比RPC更為靈活,服務提供方和調用方的依賴隻依靠一紙契約,不存在代碼級别的強依賴,這在強調快速演化的微服務環境下,顯得更為合适,至于注重通信速度還是友善靈活性,具體情況具體考慮。

探究Dubbo的ExtensionLoader

三、如何使用Dubbo

由于Dubbo無縫的內建了spring,是以我們使用起來還是很友善的,

本地服務:(Spring配置)

local.xml

<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />

 <bean id=“xxxAction” class=“com.xxx.XxxAction”>
     <property name=“xxxService” ref=“xxxService” />
 </bean>
           

遠端服務:(Spring配置)

在本地服務的基礎上,隻需做簡單配置,即可完成遠端化:

  • 将上面的local.xml配置拆分成兩份,将服務定義部分放在服務提供方remote-provider.xml,将服務引用部分放在服務消費方remote-consumer.xml。
  • 并在提供方增加暴露服務配置dubbo:service,在消費方增加引用服務配置dubbo:reference。

如下:

服務提供者:remote-provider.xml

<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” /> <!-- 和本地服務一樣實作遠端服務 -->

 <dubbo:service interface=“com.xxx.XxxService” ref=“xxxService” /> <!-- 增加暴露遠端服務配置 -->
           

服務消費者:remote-consumer.xml

<dubbo:reference id=“xxxService” interface=“com.xxx.XxxService” /> <!-- 增加引用遠端服務配置 -->

 <bean id=“xxxAction” class=“com.xxx.XxxAction”> <!-- 和本地服務一樣使用遠端服務 -->
     <property name=“xxxService” ref=“xxxService” />
 </bean>
           

Dubbo采用全Spring配置方式,透明化接入應用,對應用沒有任何API侵入,隻需用Spring加載Dubbo的配置即可,Dubbo基于Spring的Schema擴充進行加載。

1.示例

服務提供者

定義服務接口: (該接口需單獨打包,在服務提供方和消費方共享)

package com.alibaba.dubbo.demo;

public interface DemoService {

    String sayHello(String name);

}
           

在服務提供方實作接口:(對服務消費方隐藏實作)

package com.alibaba.dubbo.demo.provider;

import com.alibaba.dubbo.demo.DemoService;

public class DemoServiceImpl implements DemoService {

    public String sayHello(String name) {
        return "Hello " + name;
    }

}
           

用Spring配置聲明暴露服務:provider.xml

<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
      xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

      <!-- 提供方應用資訊,用于計算依賴關系 -->
      <dubbo:application name="hello-world-app"  />

     <!-- 使用multicast廣播注冊中心暴露服務位址 -->
     <dubbo:registry address="multicast://224.5.6.7:1234" />

     <!-- 用dubbo協定在端口暴露服務 -->
     <dubbo:protocol name="dubbo" port="20880" />

     <!-- 聲明需要暴露的服務接口 -->
     <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />

     <!-- 和本地bean一樣實作服務 -->
     <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />

 </beans>
           

加載Spring配置:

import org.springframework.context.support.ClassPathXmlApplicationContext;

  public class Provider {

      public static void main(String[] args) throws Exception {
          ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"http://10.20.160.198/wiki/display/dubbo/provider.xml"});
          context.start();

          System.in.read(); // 按任意鍵退出
     }

 }
           

服務消費者

通過Spring配置引用遠端服務:consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
      xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

      <!-- 消費方應用名,用于計算依賴關系,不是比對條件,不要與提供方一樣 -->
      <dubbo:application name="consumer-of-helloworld-app"  />

     <!-- 使用multicast廣播注冊中心暴露發現服務位址 -->
     <dubbo:registry address="multicast://224.5.6.7:1234" />

     <!-- 生成遠端服務代理,可以和本地bean一樣使用demoService -->
     <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" />

 </beans>
           

加載Spring配置,并調用遠端服務:(也可以使用IoC注入)

import org.springframework.context.support.ClassPathXmlApplicationContext;
  import com.alibaba.dubbo.demo.DemoService;

  public class Consumer {

      public static void main(String[] args) throws Exception {
          ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"http://10.20.160.198/wiki/display/dubbo/consumer.xml"});
          context.start();

         DemoService demoService = (DemoService)context.getBean("demoService"); // 擷取遠端服務代理
         String hello = demoService.sayHello("world"); // 執行遠端方法

         System.out.println( hello ); // 顯示調用結果
     }

 }
           

2.其他廣播方式

示例中使用的是multicast廣播暴露和發現服務的,當然還有其他的方式,現在使用最多的是ZooKeeper

如果使用ZooKeeper則配置修改為:

<dubbo:registry  address="multicast://224.5.6.7:1234" />
 替換為
 <dubbo:registry protocol="zookeeper" address="192.168.17.129:2181,192.168.17.129:2182,192.168.17.129:2183" /> 或者
 <dubbo:registry address="zookeeper://192.168.17.129:2181?backup=192.168.17.129:2182,192.168.17.129:2183" />
           

服務提供者和服務消費者做相同的修改

3.說明

以上是Dubbo的XML配置,Dubbo還支援屬性配置,注解配置,API配置,下面介紹下API配置,另外兩種配置方式,感興趣的朋友可以去Dubbo官網去看下:Dubbo

如果不想使用Spring配置,而希望通過API的方式進行調用(官方不推薦)則

(1) 服務提供者:

import com.alibaba.dubbo.rpc.config.ApplicationConfig;
  import com.alibaba.dubbo.rpc.config.RegistryConfig;
  import com.alibaba.dubbo.rpc.config.ProviderConfig;
  import com.alibaba.dubbo.rpc.config.ServiceConfig;
  import com.xxx.XxxService;
  import com.xxx.XxxServiceImpl;

  // 服務實作
  XxxService xxxService = new XxxServiceImpl();

 // 目前應用配置
 ApplicationConfig application = new ApplicationConfig();
 application.setName("xxx");

 // 連接配接注冊中心配置
 RegistryConfig registry = new RegistryConfig();
 registry.setAddress("10.20.130.230:9090");
 registry.setUsername("aaa");
 registry.setPassword("bbb");

 // 服務提供者協定配置
 ProtocolConfig protocol = new ProtocolConfig();
 protocol.setName("dubbo");
 protocol.setPort();
 protocol.setThreads();

 // 注意:ServiceConfig為重對象,内部封裝了與注冊中心的連接配接,以及開啟服務端口

 // 服務提供者暴露服務配置
 ServiceConfig<XxxService> service = new ServiceConfig<XxxService>(); // 此執行個體很重,封裝了與注冊中心的連接配接,請自行緩存,否則可能造成記憶體和連接配接洩漏
 service.setApplication(application);
 service.setRegistry(registry); // 多個注冊中心可以用setRegistries()
 service.setProtocol(protocol); // 多個協定可以用setProtocols()
 service.setInterface(XxxService.class);
 service.setRef(xxxService);
 service.setVersion("1.0.0");

 // 暴露及注冊服務
 service.export();
           

(2) 服務消費者:

import com.alibaba.dubbo.rpc.config.ApplicationConfig;
  import com.alibaba.dubbo.rpc.config.RegistryConfig;
  import com.alibaba.dubbo.rpc.config.ConsumerConfig;
  import com.alibaba.dubbo.rpc.config.ReferenceConfig;
  import com.xxx.XxxService;

  // 目前應用配置
  ApplicationConfig application = new ApplicationConfig();
  application.setName("yyy");

 // 連接配接注冊中心配置
 RegistryConfig registry = new RegistryConfig();
 registry.setAddress("10.20.130.230:9090");
 registry.setUsername("aaa");
 registry.setPassword("bbb");

 // 注意:ReferenceConfig為重對象,内部封裝了與注冊中心的連接配接,以及與服務提供方的連接配接

 // 引用遠端服務
 ReferenceConfig<XxxService> reference = new ReferenceConfig<XxxService>(); // 此執行個體很重,封裝了與注冊中心的連接配接以及與提供者的連接配接,請自行緩存,否則可能造成記憶體和連接配接洩漏
 reference.setApplication(application);
 reference.setRegistry(registry); // 多個注冊中心可以用setRegistries()
 reference.setInterface(XxxService.class);
 reference.setVersion("1.0.0");

 // 和本地bean一樣使用xxxService
 XxxService xxxService = reference.get(); // 注意:此代理對象内部封裝了所有通訊細節,對象較重,請緩存複用
           

四、Dubbo的一些相關疑問

1.Dubbo适用于哪些場景?

當網站變大後,不可避免的需要拆分應用進行服務化,以提高開發效率,調優性能,節省關鍵競争資源等。 

當服務越來越多時,服務的URL位址資訊就會爆炸式增長,配置管理變得非常困難,F5硬體負載均衡器的單點壓力也越來越大。 

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

接着,服務的調用量越來越大,服務的容量問題就暴露出來,這個服務需要多少機器支撐?什麼時候該加機器?等等…… 

在遇到這些問題時,都可以用Dubbo來解決。 

可參見:Dubbo的背景及需求

2.Dubbo的需求和依賴情況?

Dubbo運作JDK1.5之上,預設依賴javassist、netty、spring等包,但不是必須依賴,通過配置Dubbo可不依賴任何三方庫運作。 

可參見:使用者指南 - 依賴

3.Dubbo的性能如何?

Dubbo通過長連接配接減少握手,通過NIO及線程池在單連接配接上并發拼包處理消息,通過二進制流壓縮資料,比正常HTTP等短連接配接協定更快。在阿裡巴巴内部,每天支撐2000多個服務,30多億通路量,最大單機支撐每天近1億通路量。 

可參見:Dubbo性能測試報告

4.和淘寶HSF相比,Dubbo的特點是什麼?

  • Dubbo比HSF的部署方式更輕量,HSF要求使用指定的JBoss等容器,還需要在JBoss等容器中加入sar包擴充,對使用者運作環境的侵入性大,如果你要運作在Weblogic或Websphere等其它容器上,需要自行擴充容器以相容HSF的ClassLoader加載,而Dubbo沒有任何要求,可運作在任何Java環境中。 
  • Dubbo比HSF的擴充性更好,很友善二次開發,一個架構不可能覆寫所有需求,Dubbo始終保持平等對待第三方理念,即所有功能,都可以在不修改Dubbo原生代碼的情況下,在外圍擴充,包括Dubbo自己内置的功能,也和第三方一樣,是通過擴充的方式實作的,而HSF如果你要加功能或替換某部分實作是很困難的,比如支付寶和淘寶用的就是不同的HSF分支,因為加功能時改了核心代碼,不得不拷一個分支單獨發展,HSF現階段就算開源出來,也很難複用,除非對架構重寫。 
  • HSF依賴比較多内部系統,比如配置中心,通知中心,監控中心,單點登入等等,如果要開源還需要做很多剝離工作,而Dubbo為每個系統的內建都留出了擴充點,并已梳理幹清所有依賴,同時為開源社群提供了替代方案,使用者可以直接使用。 
  • Dubbo比HSF的功能更多,除了ClassLoader隔離,Dubbo基本上是HSF的超集,Dubbo也支援更多協定,更多注冊中心的內建,以适應更多的網站架構。

5.Dubbo在安全機制方面是如何解決的?

Dubbo主要針對内部服務,對外的服務,阿裡有開放平台來處理安全和流控,是以Dubbo在安全方面實作的功能較少,基本上隻防君子不防小人,隻防止誤調用。 

Dubbo通過Token令牌防止使用者繞過注冊中心直連,然後在注冊中心上管理授權。Dubbo還提供服務黑白名單,來控制服務所允許的調用方。 

可參見:Dubbo的令牌驗證

五、注冊中心

探究Dubbo的ExtensionLoader

流程:

  • 1.服務提供者啟動時向/dubbo/com.foo.BarService/providers目錄下寫入URL
  • 2.服務消費者啟動時訂閱/dubbo/com.foo.BarService/providers目錄下的URL向/dubbo/com.foo.BarService/consumers目錄下寫入自己的URL
  • 3.監控中心啟動時訂閱/dubbo/com.foo.BarService目錄下的所有提供者和消費者URL

支援以下功能:

  • 1.當提供者出現斷電等異常停機時,注冊中心能自動删除提供者資訊。
  • 2.當注冊中心重新開機時,能自動恢複注冊資料,以及訂閱請求。
  • 3.當會話過期時,能自動恢複注冊資料,以及訂閱請求。
  • 4.當設定<dubbo:registry check="false" />時,記錄失敗注冊和訂閱請求,背景定時重試。
  • 5.可通過<dubbo:registry username="admin" password="1234" />設定zookeeper登入資訊。
  • 6.可通過<dubbo:registry group="dubbo" />設定zookeeper的根節點,不設定将使用無根樹。
  • 7.支援号通配符<dubbo:reference group="" version="*" />,可訂閱服務的所有分組和所有版本的提供者。

注:阿裡内部并沒有采用Zookeeper做為注冊中心,而是使用自己實作的基于資料庫的注冊中心,即:Zookeeper注冊中心并沒有在阿裡内部長時間運作的可靠性保障,此Zookeeper橋接實作隻為開源版本提供,其可靠性依賴于Zookeeper本身的可靠性。

更多springboot-dubbo配置可以參考:

https://github.com/JeffLi1993/springboot-learning-example/blob/master/springboot-dubbo-server/DubboProperties.md

更多springboot的Demo示範案例:

https://github.com/JeffLi1993/springboot-learning-example

參考:

https://www.jianshu.com/p/0cd474485302

https://blog.51cto.com/developerycj/2050104

繼續閱讀