java開發(fā)分布式服務(wù)框架Dubbo原理機制詳解
前言
在介紹Dubbo之前先了解一下基本概念:
Dubbo是一個RPC
框架,RPC
,即Remote Procedure Call
(遠(yuǎn)程過程調(diào)用),相對的就是本地過程調(diào)用,在分布式架構(gòu)之前的單體應(yīng)用架構(gòu)和垂直應(yīng)用架構(gòu)運用的都是本地過程調(diào)用。它允許程序調(diào)用另外一個地址空間(通常是網(wǎng)絡(luò)共享的另外一臺機器)的過程或函數(shù),并且不用程序員顯式編碼這個遠(yuǎn)程調(diào)用的細(xì)節(jié)。
而分布式架構(gòu)應(yīng)用與應(yīng)用之間的遠(yuǎn)程調(diào)用就需要RPC
框架來做,目的就是為了讓遠(yuǎn)程調(diào)用像本地調(diào)用一樣簡單。
Dubbo框架有以下部件
Consumer
即調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費方,消費者需要面向接口編程,知道了哪些接口可以調(diào)用了,具體實現(xiàn)需要框架提供一個代理類來為接口提供具體實現(xiàn),讓消費者只管調(diào)用什么接口,而具體實現(xiàn)的獲取由代理類來處理。
消費者還需要提供調(diào)用方法名以及方法的參數(shù)值。
但是代理類此時還不知道需要調(diào)用哪個服務(wù)器上的遠(yuǎn)程方法,此時需要一個注冊中心,通過注冊中心獲取可以調(diào)用的遠(yuǎn)程服務(wù)列表。
遠(yuǎn)程服務(wù)器一般都是集群部署,那么調(diào)用哪個服務(wù)器則需要通過負(fù)載均衡來選擇一個最合適的服務(wù)器來調(diào)用。
同時還需要有集群容錯機制,因為各種原因,可能遠(yuǎn)程調(diào)用會失敗,此時需要容錯機制來重試調(diào)用,保證遠(yuǎn)程調(diào)用的穩(wěn)定性。
同時與服務(wù)提供方約定好通信協(xié)議和序列化格式,方便通信以及數(shù)據(jù)傳輸。
Provider
即暴露服務(wù)的服務(wù)提供方,服務(wù)提供方內(nèi)部實現(xiàn)具體的接口,然后將接口暴露出去,再將服務(wù)注冊到注冊中心,服務(wù)消費方調(diào)用服務(wù),提供者接收到調(diào)用請求后,通過約定好的通信協(xié)議來處理該請求,然后做反序列化,完成后,將請求放入線程池中處理,某個線程接收到這個請求然后找到對應(yīng)的接口實現(xiàn)進行調(diào)用,然后將調(diào)用結(jié)果原路返回。
Registry
即服務(wù)注冊與發(fā)現(xiàn)的注冊中心,注冊中心負(fù)責(zé)服務(wù)地址的注冊與查找,相當(dāng)于服務(wù)目錄,服務(wù)提供者和消費者只會再啟動時與注冊中心交互,注冊中心不轉(zhuǎn)發(fā)請求,壓力小。
注冊中心還可以集中化處理配置以及動態(tài)地將變更通知訂閱方。
但是為什么需要注冊中心呢?沒有注冊中心不可以嗎?
在沒有注冊中心,各服務(wù)之間的調(diào)用關(guān)系是這樣的:
當(dāng)服務(wù)越來越多時,服務(wù)URL配置管理變得非常困難,硬件負(fù)載均衡器的單點壓力也越來越大,而有了注冊中心之后,就可以實現(xiàn)服務(wù)的統(tǒng)一管理,并且實現(xiàn)軟負(fù)載均衡,降低硬件成本,以下為注冊中心示意圖:
Monitor
即統(tǒng)計服務(wù)調(diào)用次數(shù)和調(diào)用時間的監(jiān)控中心,面對眾多服務(wù),精細(xì)化的監(jiān)控和方便的運維是不可或缺的,對后期維護相當(dāng)重要。
Container
即服務(wù)運行的容器。
架構(gòu)
圖中的各個節(jié)點充當(dāng)?shù)慕巧呀?jīng)介紹過了,以下是各節(jié)點之間調(diào)用關(guān)系:
Container
服務(wù)容器負(fù)責(zé)啟動,加載以及運行
Provider
服務(wù)提供者Provider
服務(wù)提供者啟動時,需要將自身暴露出去讓遠(yuǎn)程服務(wù)器可以發(fā)現(xiàn),同時向Registry
注冊中心注冊自己提供的服務(wù)
Consumer
服務(wù)消費者啟動時,向Registry
注冊中心訂閱所需要的服務(wù)
Registry
注冊中心返回服務(wù)提供者列表給消費者,同時如果發(fā)生變更,注冊中心將基于長連接推送實時數(shù)據(jù)給消費者
服務(wù)消費者需要調(diào)用遠(yuǎn)程服務(wù)時,會從提供者的地址列表中,基于負(fù)載均衡算法選出一臺提供者服務(wù)器進行調(diào)用,如果調(diào)用失敗,會基于集群容錯策略進行調(diào)用重試
服務(wù)消費者與提供者會在內(nèi)存中統(tǒng)計調(diào)用次數(shù)和調(diào)用時間,然后通過定時任務(wù)將數(shù)據(jù)發(fā)送給Monitor
監(jiān)控中心
高可用性
- 監(jiān)控中心宕機后不會對服務(wù)造成影響,只是丟失部分統(tǒng)計數(shù)據(jù)
- 注冊中心集群后,任意一臺宕機后,將自動切換到其他注冊中心
- 當(dāng)所有注冊中心均宕機后,服務(wù)提供者和消費者之間仍然能通過本地記錄了彼此信息的緩存進行通訊,但是如果一方產(chǎn)生變更,另外一方無法感知
- 服務(wù)提供者無狀態(tài),任意一臺服務(wù)器宕機后不影響使用,會有其他服務(wù)提供者提供服務(wù)
- 當(dāng)所有服務(wù)提供者宕機后,服務(wù)消費者無法正常使用,將進行無限次重連等待服務(wù)提供者重新連線恢復(fù)
框架設(shè)計
大的分層為Business(業(yè)務(wù)邏輯層)、RPC層和Remoting層。
再細(xì)分下來,Dubbo一共有十層架構(gòu),作用分別如下:
Service
,業(yè)務(wù)層,即日常開發(fā)中的業(yè)務(wù)邏輯層
Config
,配置層,對外配置接口,以ServiceConfig
和ReferenceConfig
為中心,可以直接初始化配置類,也可以通過Spring解析配置生成配置類
Proxy
,服務(wù)代理層,服務(wù)接口透明代理,生成服務(wù)的客戶端Stub
和客戶端Skeleton
,負(fù)責(zé)遠(yuǎn)程調(diào)用和返回結(jié)果
Registry
,注冊中心層,封裝服務(wù)地址的注冊與發(fā)現(xiàn),以服務(wù)URL為中心,拓展接口為RegistryFactory
,Registry
,RegistryService
Cluster
路由和集群容錯層,封裝了多個提供者的路由、負(fù)載均衡以及集群容錯,并橋接注冊中心,負(fù)責(zé)通過負(fù)載均衡選取調(diào)用具體的節(jié)點,處理特殊調(diào)用請求和負(fù)責(zé)遠(yuǎn)程調(diào)用失敗的容錯措施
Monitor
,監(jiān)控層,負(fù)責(zé)監(jiān)控統(tǒng)計RPC調(diào)用次數(shù)和調(diào)用時間
Portocol
,遠(yuǎn)程調(diào)用層,主要封裝RPC遠(yuǎn)程調(diào)用方法
Exchange
,信息交換層,用于封裝請求響應(yīng)模型
Transport
,網(wǎng)絡(luò)傳輸層,抽象化網(wǎng)絡(luò)傳輸統(tǒng)一接口,有Mina
和Netty
可供使用
Serialize
,序列化層,將數(shù)據(jù)序列化成二進制流進行傳輸,也可以反序列化接收數(shù)據(jù)
服務(wù)暴露過程
首先Provider啟動,Protocal通過Proxy代理將需要暴露的接口封裝成Invoker,是一個可執(zhí)行體,然后通過Exporter包裝并發(fā)送到注冊中心完成注冊,至此服務(wù)就暴露完成。
服務(wù)消費過程
注:上圖中藍色部分為服務(wù)消費者,綠色部分為服務(wù)提供者。
服務(wù)消費者啟動時會向注冊中心訂閱并拉取所需服務(wù)提供者的信息,并保存到本地緩存,由此即使所有注冊中心宕機后,服務(wù)提供者和服務(wù)消費者也可以通過本地緩存進行通訊,只是一方出現(xiàn)了信息變更,另一方無法感知,但并不影響服務(wù)的進行。
之后整個服務(wù)消費流程從圖中的Proxy開始,由代理類完成處理,以此到達透明無感知。
ProxyFactory
生成一個Proxy
代理類,Proxy持有一個Invoker可執(zhí)行對象,調(diào)用invoke
之后需要通過Cluster
從Directory
中獲取所有可調(diào)用的遠(yuǎn)程服務(wù)Invoker列表,如果配置了某些路由規(guī)則,還需要再過濾一遍Invoker列表。
剩下的Invoker再通過LoadBalance
做負(fù)載均衡選取一個,還需要再通過Filter進行一些數(shù)據(jù)統(tǒng)計,之后將這些數(shù)據(jù)保存下來,定時發(fā)送給Monitor
。
接下來用Client
做數(shù)據(jù)傳輸,一般用Netty
進行傳輸。
傳輸需要通過Codec
接口進行協(xié)議構(gòu)造,然后再通過Serialization
進行序列化,最后將序列化后的二進制流發(fā)送至給對應(yīng)的服務(wù)提供者。
服務(wù)提供者接收到二進制流后也會進行Codec協(xié)議處理,然后進行反序列化(此處的處理與傳輸之前的處理是呈對稱的)后將請求放入線程池中處理,某個線程會根據(jù)請求找到對應(yīng)的Exporter
,然后再通過Filter進行層層過濾得到Invoker,最終調(diào)用對應(yīng)的實現(xiàn)類然后將結(jié)果原路返回。
如有錯誤或不足歡迎評論指正。
以上就是java開發(fā)分布式服務(wù)框架Dubbo原理機制詳解的詳細(xì)內(nèi)容,更多關(guān)于Dubbo分布式服務(wù)框架原理機制的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java使用poi-tl1.9.1生成Word文檔的技巧分享
本文將簡單介紹poi-tl的相關(guān)知識,通過一個實際的案例實踐,充分介紹如何利用poi-tl進行目標(biāo)文檔的生成,同時分享幾個不同的office版本如何進行圖表生成的解決方案,需要的朋友可以參考下2023-09-09Java利用LocalDate類實現(xiàn)日歷設(shè)計
java中做時間處理時一般會采用java.util.Date,但是相比于Date來說,還有更好的選擇--java.time.LocalDate。本文就來用LocalDate類實現(xiàn)日歷設(shè)計,感興趣的可以動手嘗試一下2022-07-07Java使用kafka發(fā)送和生產(chǎn)消息的示例
本篇文章主要介紹了Java使用kafka發(fā)送和生產(chǎn)消息的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04一篇文章帶你了解Maven的坐標(biāo)概念以及依賴管理
這篇文章主要為大家介紹了Maven的坐標(biāo)概念以及依賴管理,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01java.lang.NullPointerException 如何處理空指針異常的實現(xiàn)
這篇文章主要介紹了java.lang.NullPointerException 如何處理空指針異常的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12完美解決idea光標(biāo)變成了insert光標(biāo)狀態(tài)的問題
這篇文章主要介紹了完美解決idea光標(biāo)變成了insert光標(biāo)狀態(tài)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02