java開(kāi)發(fā)分布式服務(wù)框架Dubbo原理機(jī)制詳解
前言
在介紹Dubbo之前先了解一下基本概念:
Dubbo是一個(gè)RPC框架,RPC,即Remote Procedure Call(遠(yuǎn)程過(guò)程調(diào)用),相對(duì)的就是本地過(guò)程調(diào)用,在分布式架構(gòu)之前的單體應(yīng)用架構(gòu)和垂直應(yīng)用架構(gòu)運(yùn)用的都是本地過(guò)程調(diào)用。它允許程序調(diào)用另外一個(gè)地址空間(通常是網(wǎng)絡(luò)共享的另外一臺(tái)機(jī)器)的過(guò)程或函數(shù),并且不用程序員顯式編碼這個(gè)遠(yuǎn)程調(diào)用的細(xì)節(jié)。
而分布式架構(gòu)應(yīng)用與應(yīng)用之間的遠(yuǎn)程調(diào)用就需要RPC框架來(lái)做,目的就是為了讓遠(yuǎn)程調(diào)用像本地調(diào)用一樣簡(jiǎn)單。

Dubbo框架有以下部件
Consumer
即調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費(fèi)方,消費(fèi)者需要面向接口編程,知道了哪些接口可以調(diào)用了,具體實(shí)現(xiàn)需要框架提供一個(gè)代理類(lèi)來(lái)為接口提供具體實(shí)現(xiàn),讓消費(fèi)者只管調(diào)用什么接口,而具體實(shí)現(xiàn)的獲取由代理類(lèi)來(lái)處理。
消費(fèi)者還需要提供調(diào)用方法名以及方法的參數(shù)值。
但是代理類(lèi)此時(shí)還不知道需要調(diào)用哪個(gè)服務(wù)器上的遠(yuǎn)程方法,此時(shí)需要一個(gè)注冊(cè)中心,通過(guò)注冊(cè)中心獲取可以調(diào)用的遠(yuǎn)程服務(wù)列表。
遠(yuǎn)程服務(wù)器一般都是集群部署,那么調(diào)用哪個(gè)服務(wù)器則需要通過(guò)負(fù)載均衡來(lái)選擇一個(gè)最合適的服務(wù)器來(lái)調(diào)用。
同時(shí)還需要有集群容錯(cuò)機(jī)制,因?yàn)楦鞣N原因,可能遠(yuǎn)程調(diào)用會(huì)失敗,此時(shí)需要容錯(cuò)機(jī)制來(lái)重試調(diào)用,保證遠(yuǎn)程調(diào)用的穩(wěn)定性。
同時(shí)與服務(wù)提供方約定好通信協(xié)議和序列化格式,方便通信以及數(shù)據(jù)傳輸。
Provider
即暴露服務(wù)的服務(wù)提供方,服務(wù)提供方內(nèi)部實(shí)現(xiàn)具體的接口,然后將接口暴露出去,再將服務(wù)注冊(cè)到注冊(cè)中心,服務(wù)消費(fèi)方調(diào)用服務(wù),提供者接收到調(diào)用請(qǐng)求后,通過(guò)約定好的通信協(xié)議來(lái)處理該請(qǐng)求,然后做反序列化,完成后,將請(qǐng)求放入線(xiàn)程池中處理,某個(gè)線(xiàn)程接收到這個(gè)請(qǐng)求然后找到對(duì)應(yīng)的接口實(shí)現(xiàn)進(jìn)行調(diào)用,然后將調(diào)用結(jié)果原路返回。
Registry
即服務(wù)注冊(cè)與發(fā)現(xiàn)的注冊(cè)中心,注冊(cè)中心負(fù)責(zé)服務(wù)地址的注冊(cè)與查找,相當(dāng)于服務(wù)目錄,服務(wù)提供者和消費(fèi)者只會(huì)再啟動(dòng)時(shí)與注冊(cè)中心交互,注冊(cè)中心不轉(zhuǎn)發(fā)請(qǐng)求,壓力小。

注冊(cè)中心還可以集中化處理配置以及動(dòng)態(tài)地將變更通知訂閱方。
但是為什么需要注冊(cè)中心呢?沒(méi)有注冊(cè)中心不可以嗎?
在沒(méi)有注冊(cè)中心,各服務(wù)之間的調(diào)用關(guān)系是這樣的:

當(dāng)服務(wù)越來(lái)越多時(shí),服務(wù)URL配置管理變得非常困難,硬件負(fù)載均衡器的單點(diǎn)壓力也越來(lái)越大,而有了注冊(cè)中心之后,就可以實(shí)現(xiàn)服務(wù)的統(tǒng)一管理,并且實(shí)現(xiàn)軟負(fù)載均衡,降低硬件成本,以下為注冊(cè)中心示意圖:

Monitor
即統(tǒng)計(jì)服務(wù)調(diào)用次數(shù)和調(diào)用時(shí)間的監(jiān)控中心,面對(duì)眾多服務(wù),精細(xì)化的監(jiān)控和方便的運(yùn)維是不可或缺的,對(duì)后期維護(hù)相當(dāng)重要。
Container
即服務(wù)運(yùn)行的容器。
架構(gòu)

圖中的各個(gè)節(jié)點(diǎn)充當(dāng)?shù)慕巧呀?jīng)介紹過(guò)了,以下是各節(jié)點(diǎn)之間調(diào)用關(guān)系:
Container服務(wù)容器負(fù)責(zé)啟動(dòng),加載以及運(yùn)行
Provider服務(wù)提供者Provider服務(wù)提供者啟動(dòng)時(shí),需要將自身暴露出去讓遠(yuǎn)程服務(wù)器可以發(fā)現(xiàn),同時(shí)向Registry注冊(cè)中心注冊(cè)自己提供的服務(wù)
Consumer服務(wù)消費(fèi)者啟動(dòng)時(shí),向Registry注冊(cè)中心訂閱所需要的服務(wù)
Registry注冊(cè)中心返回服務(wù)提供者列表給消費(fèi)者,同時(shí)如果發(fā)生變更,注冊(cè)中心將基于長(zhǎng)連接推送實(shí)時(shí)數(shù)據(jù)給消費(fèi)者
服務(wù)消費(fèi)者需要調(diào)用遠(yuǎn)程服務(wù)時(shí),會(huì)從提供者的地址列表中,基于負(fù)載均衡算法選出一臺(tái)提供者服務(wù)器進(jìn)行調(diào)用,如果調(diào)用失敗,會(huì)基于集群容錯(cuò)策略進(jìn)行調(diào)用重試
服務(wù)消費(fèi)者與提供者會(huì)在內(nèi)存中統(tǒng)計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間,然后通過(guò)定時(shí)任務(wù)將數(shù)據(jù)發(fā)送給Monitor監(jiān)控中心
高可用性
- 監(jiān)控中心宕機(jī)后不會(huì)對(duì)服務(wù)造成影響,只是丟失部分統(tǒng)計(jì)數(shù)據(jù)
- 注冊(cè)中心集群后,任意一臺(tái)宕機(jī)后,將自動(dòng)切換到其他注冊(cè)中心
- 當(dāng)所有注冊(cè)中心均宕機(jī)后,服務(wù)提供者和消費(fèi)者之間仍然能通過(guò)本地記錄了彼此信息的緩存進(jìn)行通訊,但是如果一方產(chǎn)生變更,另外一方無(wú)法感知
- 服務(wù)提供者無(wú)狀態(tài),任意一臺(tái)服務(wù)器宕機(jī)后不影響使用,會(huì)有其他服務(wù)提供者提供服務(wù)
- 當(dāng)所有服務(wù)提供者宕機(jī)后,服務(wù)消費(fèi)者無(wú)法正常使用,將進(jìn)行無(wú)限次重連等待服務(wù)提供者重新連線(xiàn)恢復(fù)
框架設(shè)計(jì)

大的分層為Business(業(yè)務(wù)邏輯層)、RPC層和Remoting層。
再細(xì)分下來(lái),Dubbo一共有十層架構(gòu),作用分別如下:
Service,業(yè)務(wù)層,即日常開(kāi)發(fā)中的業(yè)務(wù)邏輯層
Config,配置層,對(duì)外配置接口,以ServiceConfig 和ReferenceConfig為中心,可以直接初始化配置類(lèi),也可以通過(guò)Spring解析配置生成配置類(lèi)
Proxy,服務(wù)代理層,服務(wù)接口透明代理,生成服務(wù)的客戶(hù)端Stub和客戶(hù)端Skeleton,負(fù)責(zé)遠(yuǎn)程調(diào)用和返回結(jié)果
Registry,注冊(cè)中心層,封裝服務(wù)地址的注冊(cè)與發(fā)現(xiàn),以服務(wù)URL為中心,拓展接口為RegistryFactory,Registry,RegistryService
Cluster路由和集群容錯(cuò)層,封裝了多個(gè)提供者的路由、負(fù)載均衡以及集群容錯(cuò),并橋接注冊(cè)中心,負(fù)責(zé)通過(guò)負(fù)載均衡選取調(diào)用具體的節(jié)點(diǎn),處理特殊調(diào)用請(qǐng)求和負(fù)責(zé)遠(yuǎn)程調(diào)用失敗的容錯(cuò)措施
Monitor,監(jiān)控層,負(fù)責(zé)監(jiān)控統(tǒng)計(jì)RPC調(diào)用次數(shù)和調(diào)用時(shí)間
Portocol,遠(yuǎn)程調(diào)用層,主要封裝RPC遠(yuǎn)程調(diào)用方法
Exchange,信息交換層,用于封裝請(qǐng)求響應(yīng)模型
Transport,網(wǎng)絡(luò)傳輸層,抽象化網(wǎng)絡(luò)傳輸統(tǒng)一接口,有Mina和Netty可供使用
Serialize,序列化層,將數(shù)據(jù)序列化成二進(jìn)制流進(jìn)行傳輸,也可以反序列化接收數(shù)據(jù)
服務(wù)暴露過(guò)程
首先Provider啟動(dòng),Protocal通過(guò)Proxy代理將需要暴露的接口封裝成Invoker,是一個(gè)可執(zhí)行體,然后通過(guò)Exporter包裝并發(fā)送到注冊(cè)中心完成注冊(cè),至此服務(wù)就暴露完成。

服務(wù)消費(fèi)過(guò)程

注:上圖中藍(lán)色部分為服務(wù)消費(fèi)者,綠色部分為服務(wù)提供者。
服務(wù)消費(fèi)者啟動(dòng)時(shí)會(huì)向注冊(cè)中心訂閱并拉取所需服務(wù)提供者的信息,并保存到本地緩存,由此即使所有注冊(cè)中心宕機(jī)后,服務(wù)提供者和服務(wù)消費(fèi)者也可以通過(guò)本地緩存進(jìn)行通訊,只是一方出現(xiàn)了信息變更,另一方無(wú)法感知,但并不影響服務(wù)的進(jìn)行。
之后整個(gè)服務(wù)消費(fèi)流程從圖中的Proxy開(kāi)始,由代理類(lèi)完成處理,以此到達(dá)透明無(wú)感知。
ProxyFactory生成一個(gè)Proxy代理類(lèi),Proxy持有一個(gè)Invoker可執(zhí)行對(duì)象,調(diào)用invoke之后需要通過(guò)Cluster從Directory中獲取所有可調(diào)用的遠(yuǎn)程服務(wù)Invoker列表,如果配置了某些路由規(guī)則,還需要再過(guò)濾一遍Invoker列表。
剩下的Invoker再通過(guò)LoadBalance做負(fù)載均衡選取一個(gè),還需要再通過(guò)Filter進(jìn)行一些數(shù)據(jù)統(tǒng)計(jì),之后將這些數(shù)據(jù)保存下來(lái),定時(shí)發(fā)送給Monitor。
接下來(lái)用Client做數(shù)據(jù)傳輸,一般用Netty進(jìn)行傳輸。
傳輸需要通過(guò)Codec接口進(jìn)行協(xié)議構(gòu)造,然后再通過(guò)Serialization進(jìn)行序列化,最后將序列化后的二進(jìn)制流發(fā)送至給對(duì)應(yīng)的服務(wù)提供者。
服務(wù)提供者接收到二進(jìn)制流后也會(huì)進(jìn)行Codec協(xié)議處理,然后進(jìn)行反序列化(此處的處理與傳輸之前的處理是呈對(duì)稱(chēng)的)后將請(qǐng)求放入線(xiàn)程池中處理,某個(gè)線(xiàn)程會(huì)根據(jù)請(qǐng)求找到對(duì)應(yīng)的Exporter,然后再通過(guò)Filter進(jìn)行層層過(guò)濾得到Invoker,最終調(diào)用對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)然后將結(jié)果原路返回。
如有錯(cuò)誤或不足歡迎評(píng)論指正。
以上就是java開(kāi)發(fā)分布式服務(wù)框架Dubbo原理機(jī)制詳解的詳細(xì)內(nèi)容,更多關(guān)于Dubbo分布式服務(wù)框架原理機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
創(chuàng)建并運(yùn)行一個(gè)java線(xiàn)程方法介紹
這篇文章主要介紹了創(chuàng)建并運(yùn)行一個(gè)java線(xiàn)程,涉及線(xiàn)程代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
java文件下載設(shè)置中文名稱(chēng)的實(shí)例(response.addHeader)
下面小編就為大家分享一篇java文件下載設(shè)置中文名稱(chēng)的實(shí)例(response.addHeader),具有很好的參考價(jià)值,希望對(duì)大家有所幫助2017-12-12
Java操作redis設(shè)置第二天凌晨過(guò)期的解決方案
這篇文章主要介紹了Java操作redis設(shè)置第二天凌晨過(guò)期的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
解決IDEA2021版compiler.automake.allow.when.app.running不存在的問(wèn)題
很多文章介紹IntelliJ IDEA開(kāi)啟熱部署功能都會(huì)寫(xiě)到在IntelliJ IDEA中的注冊(cè)表中開(kāi)啟compiler.automake.allow.when.app.running選項(xiàng),此選項(xiàng)在IntelliJ IDEA 2021.2之后的版本遷移到高級(jí)設(shè)置中,下面看下設(shè)置方法2021-09-09
淺談s:select 標(biāo)簽中l(wèi)ist存放map對(duì)象的使用
下面小編就為大家?guī)?lái)一篇淺談s:select 標(biāo)簽中l(wèi)ist存放map對(duì)象的使用。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11
Java調(diào)用Oracle存儲(chǔ)過(guò)程詳解
這篇文章主要介紹了Java調(diào)用Oracle存儲(chǔ)過(guò)程詳解的相關(guān)資料,需要的朋友可以參考下2017-02-02

