目錄
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方法導出服務,並註冊到註冊中心
如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×tamp=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 服務消費者調用服務
首先ReferenceConfig的init方法調用Protocol的refer方法 生成Invoker實例(如上圖中的紅色部分), 這是服務消費的關鍵。 接下來把Invoker轉換爲客戶端所需接口(如:DemoService)。 每種協議如RMI/Dubbo/Web service等它們在調用refer方法 生成Invoker實例的細節。 |
核心方法refer、subscribe()
4.源碼模塊解析
4.1 包組織結構
- 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 層次結構
- 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
核心類
接口 RegistryFactory、Registry
AbstractRegistry 以及 ZookeeperRegistry、ZookeeperRegistryFactory
以zk爲例
支持以下功能:
流程說明:
- 提供者啓動時向/dubbo/com.foo.BarService/providers目錄下寫入自己的URL地址。
- 消費者啓動時訂閱/dubbo/com.foo.BarService/providers的提供者URL地址。並向/dubbo/com.foo.BarService/consumers下寫入自己的URL地址。
- 監控中心啓動時訂閱/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
- DubboProtocol採用單一長連接和NIO異步通訊,適用於小數據量大併發的服務調用,及consumer cnt >> provider cnt。通過單一連接,保證單一消費者不會壓死提供者,長連接,減少連接握手驗證等,並使用異步IO,複用線程池,防止C10K問題。
- dubbo協議底層直接使用了Netty框架,在dubbo協議中,分爲三種調用方式:同步(默認)、異步和OneWay,同步就是阻塞等拿到被調用方的結果再返回;異步不等待被調用者的處理結果就直接返回,但需要等到被調用者接收到異步請求的應答;OneWay(單向調用)在很多MQ和RPC框架中都有出現,即調用方只負責調用一次,不管被調用方是否接收到該請求,更不會去理會被調用方的任何應答,OneWay一般只會在無需保證調用結果的時候使用。
4.2.6 Exchange信息交換層
主要功能:封裝請求響應模式,同步轉異步,處理各種協議的通信請求,支持netty、mina、http等,默認採用Netty進行通信
接口 Server、Channel、Client
NettyClient、NettyServer
4.2.7 Serialize數據序列化層
數據序列化層和可複用的一些工具,包括序列化線程池等。dubbo協議缺省爲hessian2,rmi協議缺省爲java,http協議缺省爲json
接口 ThreadPool、Serialization
FixedThreadPool、 Hessian2Serialization