【微服務】dubbo源碼閱讀(一)

目錄

1.簡介

1.1 背景知識

1.2 應用場景

3.流程

3.1服務提供者服務導出

3.2 服務消費者調用服務

4.源碼模塊解析

4.1 包組織結構

4.2 層次結構

4.2.1 config配置

4.2.2 *Proxy 服務代理層

4.2.3 Registry註冊中心層 

4.2.4 Cluster 路由層 

4.2.5 Protocol遠程調用層

4.2.6 Exchange信息交換層 

4.2.7 Serialize數據序列化層 


1.簡介

Apache Dubbo |ˈdʌbəʊ| 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的RPC遠程方法調用,智能容錯和負載均衡,以及服務自動註冊和發現。官方文檔

類似與Spring mvc 是http層的框架,使用http協議進行通信並調用http web服務 @requestMapping暴露的接口,Dubbo可以基於TCP+自定義協議調用服務暴露出來的遠程方法。

1.1 背景知識

  • 遠程調用 : RMI、hassian、webservice、thrift 
  • 通信交互 : HTTP、mina、netty
  • 序列化 : hessian2、 java、json
  • 容器 : jetty、spring
  • 多線程 : 異步、線程池
  • 服務註冊發現 : zookeeper、redis

1.2 應用場景

  • 作爲對內提供服務應用的容器
  • 拆分複雜Web應用到服務容器
  • 應用負載均衡協調
  • 應用服務治理

3.流程

0.start 容器啓動     1.register:服務提供者啓動-註冊       2.subscribe:服務消費者啓動-訂閱註冊中心 

3.notify:註冊中心通知消費者 有新的服務提供者

4.invoke:RPC遠程調用

5.count:監控

3.1服務提供者服務導出

服務提供者配置如下

<beans>
    <!-- 服務提供者的應用程序名稱,用於跟蹤依賴關係 -->
    <dubbo:application name="demo-provider"/>

    <!-- 利用註冊中心導出服務 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!-- 使用dubbo協議在端口20880上導出服務 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!-- 服務實現,方式與常規bean一樣 -->
    <bean id="demoService" class="demo.DemoServiceImpl"/>

    <!-- 聲明要導出的服務接口 -->
    <dubbo:service interface="demo.DemoService" ref="demoService"/>
</beans>

首先ServiceConfig類拿到對外提供服務的實際類ref(如上配置:DemoServiceImpl),然後通過ProxyFactory類的getInvoker方法使用ref生成一個AbstractProxyInvoker實例,到這一步就完成具體服務到Invoker的轉化。

接下來就是Invoker轉換到Exporter的過程,如下圖,通過Protocol的export方法導出服務,並註冊到註冊中心
/dev-guide/images/dubbo-export.jpg

DubboProtocol,以上的暴露的服務

url=dubbo://xx.xx.xx.xxx:20880/demo.DemoService?anyhost=true&application=demo-provider&bind.ip=xx.xx.xx.xxx&bind.port=20880&channel.readonly.sent=true&codec=dubbo&dubbo=2.6.2&generic=false&interface=demo.DemoService&methods=sayHello&pid=30185&side=provider&timestamp=1575978129988

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url);
        DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
        exporterMap.put(key, exporter);

        ...

        openServer(url);
        optimizeSerialization(url);
        return exporter;
    }

3.2 服務消費者調用服務

首先ReferenceConfiginit方法調用Protocolrefer方法

生成Invoker實例(如上圖中的紅色部分),

這是服務消費的關鍵。

接下來把Invoker轉換爲客戶端所需接口(如:DemoService)。

每種協議如RMI/Dubbo/Web service等它們在調用refer方法

生成Invoker實例的細節。

/dev-guide/images/dubbo-refer.jpg

design-step-4/dev-guide/images/dubbo-extension.jpg

核心方法refersubscribe()

4.源碼模塊解析

4.1 包組織結構

/dev-guide/images/dubbo-modules.jpg

 

  • dubbo-common 公共邏輯模塊:包括 Util 類和通用模型。
  • dubbo-remoting 遠程通訊模塊:相當於 Dubbo 協議的實現,如果 RPC 用 RMI協議則不需要使用此包。
  • dubbo-rpc 遠程調用模塊:抽象各種協議,以及動態代理,只包含一對一的調用,不關心集羣的管理。
  • dubbo-cluster 集羣模塊:多個provider包成一個,負載均衡, 容錯,路由等,集羣地址列表可靜態配置,也可由註冊中心下發。
  • dubbo-registry 註冊中心模塊:基於註冊中心下發地址的集羣方式,以及對各種註冊中心的抽象。
  • dubbo-monitor 監控模塊:統計服務調用次數,調用時間的,調用鏈跟蹤的服務。
  • dubbo-config 配置模塊:是 Dubbo 對外的 API,用戶通過 Config 使用Dubbo,隱藏 Dubbo 所有細節。
  • dubbo-container 容器模塊:是一個 Standlone 的容器,以簡單的 Main 加載 Spring 啓動,因爲服務通常不需要 Tomcat/JBoss 等 Web 容器的特性,沒必要用 Web 容器去加載服務。

4.2 層次結構

https://img-blog.csdnimg.cn/20190826143519959.png

  • Service()服務層:業務實現,包含服務提供者和消費者的實現類和接口類
  • Config配置層(dubbo-config): 服務代理層,主要結合SPI機制,動態選取不通的配置類,參見SPI機制
  • Registry註冊層(dubbo-registry) :負責註冊和發現Dubbo服務,以及對Dubbo服務的監聽
  • Cluster路由層(dubbo-cluster):服務的路由、負載和失敗重試策略
  • Protocol協議層(dubbo-rpc):協議的轉換和過濾
  • Exchange信息交換層 (dubbo-remoting) 
  • Transport傳輸層(dubbo-remoting):抽象Netty、Mina爲統一接口,數據通信傳輸
  • Serialize序列化層(dubbo-common):根據不同協議對數據進行序列化

4.2.1 config配置

負責所有dubbo相關的xml配置和註釋配置轉換爲config對象 ( dubbo.xsd )

api配置的對象類,用於生成對應的register,protocol等對象

核心類有

  • ServiceBean(對應provider端的<dubbo:service interface="demo.DemoService" ref="demoService"/>)
  • ReferenceBean (consumer端的<dubbo:reference id="demoService" check="false" interface="demo.DemoService"/>)
  • ProtocolConfig(provider端的<dubbo:protocol name="dubbo" port="20880"/>)
  • RegisterConfig (<dubbo:registry address="zookeeper://127.0.0.1:2181"/>)

4.2.2 *Proxy 服務代理層

負責生成消費者的代理對象,以及服務提供方Provider的Invoker
ProxyFactory接口的2種實現 JdkProxyFactory、JavassistProxyFactory,原理請見動態代理

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

4.2.3 Registry註冊中心層 

負責服務註冊與查詢服務,以及註冊服務的本地緩存<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
支持多種協議註冊發現服務,例如redis、zookeeper、Multicast

核心類
接口 RegistryFactoryRegistry
AbstractRegistry 以及 ZookeeperRegistryZookeeperRegistryFactory

以zk爲例

支持以下功能:

當提供者出現斷電等異常停機時,註冊中心能自動刪除提供者信息。
當註冊中心重啓時,能自動恢復註冊數據,以及訂閱請求。
當會話過期時,能自動恢復註冊數據,以及訂閱請求。
當設置<dubbo:registry check="false" />時,記錄失敗註冊和訂閱請求,後臺定時重試。

流程說明:

  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地址。

4.2.4 Cluster 路由層 

主要負責負載均衡的策略,以及失敗策略,缺省設置:RandomLoadBalance,FailoverCluster
支持輪詢、隨機、最少活躍、一致性哈希負載均衡策略

核心類
接口 LoadBalance、Cluster
RandomLoadBalance以及 RoundRobinLoadBalance等

各節點關係:

Invoker是Provider的一個可調用Service的抽象,Invoker封裝了Provider地址及Service接口信息

Directory代表多個Invoker,可以把它看成List<Invoker>,但與List不同的是,它的值可能是動態變化的,比如註冊中心推送變更。

Cluster將Directory中的多個Invoker僞裝成一個Invoker,對上層透明,僞裝過程包含了容錯邏輯,調用失敗後,重試另一個。

Router負責從多個Invoker中按路由規則選出子集,比如讀寫分離,應用隔離等。

LoadBalance負責從多個Invoker中選出具體的一個用於本次調用,選的過程包含了負載均衡算法,調用失敗後,需要重選。

4.2.5 Protocol遠程調用層

封裝RPC調用、支持多種RPC協議,不包含IO通信部分
支持Dubbo(默認)、RMI 、Hessian、Http、WebService、thrift等9種RPC調用方式
接口 Protocol、Exporter、Invoker
DubboProtocol、DubboInvoker、DubboExporter、DubboCodec

  1. DubboProtocol採用單一長連接和NIO異步通訊,適用於小數據量大併發的服務調用,及consumer cnt >> provider cnt。通過單一連接,保證單一消費者不會壓死提供者,長連接,減少連接握手驗證等,並使用異步IO,複用線程池,防止C10K問題。
  2. dubbo協議底層直接使用了Netty框架,在dubbo協議中,分爲三種調用方式:同步(默認)、異步和OneWay,同步就是阻塞等拿到被調用方的結果再返回;異步不等待被調用者的處理結果就直接返回,但需要等到被調用者接收到異步請求的應答;OneWay(單向調用)在很多MQ和RPC框架中都有出現,即調用方只負責調用一次,不管被調用方是否接收到該請求,更不會去理會被調用方的任何應答,OneWay一般只會在無需保證調用結果的時候使用。

4.2.6 Exchange信息交換層 

主要功能:封裝請求響應模式,同步轉異步,處理各種協議的通信請求,支持netty、mina、http等,默認採用Netty進行通信
接口 ServerChannelClient 
NettyClientNettyServer

4.2.7 Serialize數據序列化層 

數據序列化層和可複用的一些工具,包括序列化線程池等。dubbo協議缺省爲hessian2,rmi協議缺省爲java,http協議缺省爲json
接口 ThreadPoolSerialization 
FixedThreadPoolHessian2Serialization
 

 

發佈了97 篇原創文章 · 獲贊 16 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章