什么是RPC吆玖?RPC框架dubbo的核心流程

一筒溃、REST 與 RPC

1、什么是 REST 和 RPC 協(xié)議沾乘?

在單體應(yīng)用中铡羡,各模塊間的調(diào)用是通過(guò)編程語(yǔ)言級(jí)別的方法函數(shù)來(lái)實(shí)現(xiàn),但分布式系統(tǒng)運(yùn)行在多臺(tái)機(jī)器上意鲸,一般來(lái)說(shuō),每個(gè)服務(wù)實(shí)例都是一個(gè)進(jìn)程尽爆,服務(wù)間必須使用進(jìn)程間通信機(jī)制來(lái)交互怎顾,而常見(jiàn)的通信協(xié)議主要有 RPC 和 REST 協(xié)議。

(1)REST:

REST 是基于 HTTP 實(shí)現(xiàn)漱贱,使用 HTTP 協(xié)議處理數(shù)據(jù)通信槐雾,更加標(biāo)準(zhǔn)化與通用,因?yàn)闊o(wú)論哪種語(yǔ)言都支持 HTTP 協(xié)議幅狮。常見(jiàn)的 http API 都可以稱為 Rest 接口募强。REST 是一種架構(gòu)風(fēng)格,指一組架構(gòu)約束條件和原則崇摄,滿足 REST 原則的應(yīng)用程序或設(shè)計(jì)就是 RESTful擎值,RESTful 把一切內(nèi)容都視為資源。REST 強(qiáng)調(diào)組件交互的擴(kuò)展性逐抑、接口的通用性鸠儿、組件的獨(dú)立部署、以及減少交互延遲的中間件,它強(qiáng)化安全进每,也能封裝遺留系統(tǒng)汹粤。

(2)RPC:

image.png

RPC 是一種進(jìn)程間通信方式,允許像調(diào)用本地服務(wù)一樣調(diào)用遠(yuǎn)程服務(wù)田晚,通信協(xié)議大多采用二進(jìn)制方式嘱兼。

2、RPC 與 REST 的對(duì)比

image.png

(1)傳輸協(xié)議與性能:RPC 的傳輸協(xié)議靈活贤徒,可基于 TCP 實(shí)現(xiàn)芹壕,由于 TCP 協(xié)<typo id="typo-542" data-origin="的" ignoretag="true">議</typo>處于協(xié)議棧的下層,能夠更靈活地對(duì)協(xié)議字段進(jìn)行定制泞莉,讓請(qǐng)求報(bào)文體積更小哪雕,減少網(wǎng)絡(luò)開(kāi)銷(xiāo),提高傳輸性能并縮短傳輸耗時(shí)鲫趁,實(shí)現(xiàn)更大的吞吐量和并發(fā)數(shù)斯嚎。REST 的 HTTP 協(xié)議是上層協(xié)議,發(fā)送包含同等內(nèi)容的信息挨厚,請(qǐng)求中會(huì)包含很多無(wú)用的內(nèi)容堡僻,所占用的字節(jié)數(shù)比使用 TCP 協(xié)議傳輸更高,因此在同等網(wǎng)絡(luò)下疫剃,HTTP 會(huì)比基于 TCP 協(xié)議的數(shù)據(jù)傳輸效率要低钉疫,傳輸耗時(shí)更長(zhǎng),不僅如此巢价,REST 的 HTTP 大部分是通過(guò) JSON 來(lái)實(shí)現(xiàn)的牲阁,序列化也更消耗性能,但如果是基于 HTTP2.0壤躲,那么經(jīng)過(guò)封裝也是可以作為一個(gè) RPC 來(lái)使用的城菊。

(2)靈活性、開(kāi)放性與通用性:REST 通過(guò) HTTP 實(shí)現(xiàn)碉克,相對(duì)更加規(guī)范與通用凌唬,無(wú)論哪種語(yǔ)言都支持 HTTP 協(xié)議,所以 REST 的調(diào)用和測(cè)試都很方便漏麦,但使用 RPC 則會(huì)有很多約束客税,而如果 RPC 需要對(duì)外<typo id="typo-913" data-origin="使用" ignoretag="true">開(kāi)放</typo>的話,需要進(jìn)一步處理撕贞,靈活性不如 REST

(3)使用場(chǎng)景:REST 主要用于對(duì)外開(kāi)放的異構(gòu)環(huán)境更耻,比如瀏覽器接口調(diào)用,Api 接口調(diào)用捏膨,第三方接口調(diào)用等酥夭。RPC 主要用于公司內(nèi)部的服務(wù)調(diào)用,性能消耗低,傳輸效率高熬北,特別是大型的網(wǎng)站疙描,內(nèi)部子系統(tǒng)較多、接口非常多的情況下適合使用 RPC

二讶隐、RPC 框架

REST 和 RPC 都常用于微服務(wù)架構(gòu)中起胰,微服務(wù)的好處之一,就是不限定服務(wù)的提供方使用什么技術(shù)選型巫延,能夠?qū)崿F(xiàn)大公司跨團(tuán)隊(duì)的技術(shù)解耦效五。 但是,如果沒(méi)有統(tǒng)一的通信框架炉峰,各個(gè)團(tuán)隊(duì)的服務(wù)提供方就需要各自實(shí)現(xiàn)一套序列化畏妖、反序列化、網(wǎng)絡(luò)框架疼阔、連接池碎赢、收發(fā)線程奏寨、超時(shí)處理、狀態(tài)機(jī)等 “業(yè)務(wù)之外” 的重復(fù)技術(shù)勞動(dòng),造成整體的低效开皿。所以群嗤,統(tǒng)一通信框架把上<typo id="typo-1246" data-origin="的" ignoretag="true">述</typo> “業(yè)務(wù)之外” 的技術(shù)勞動(dòng)統(tǒng)一處理似将,是服務(wù)化首要解決的問(wèn)題屏积。

1、什么是 RPC 框架宾舅?

RPC 框架的目標(biāo)就是讓遠(yuǎn)程服務(wù)調(diào)用更簡(jiǎn)單统阿、透明,由 RPC 框架負(fù)責(zé)屏蔽底層的序列化筹我、傳輸方式和通信的細(xì)節(jié)砂吞,開(kāi)發(fā)者在使用時(shí)只需要了解誰(shuí)在什么位置提供了什么樣的遠(yuǎn)程服務(wù)接口即可,并不需要關(guān)心底層通信細(xì)節(jié)和調(diào)用過(guò)程崎溃。RPC 框架作為架構(gòu)微服務(wù)化的基礎(chǔ)組件,它能大大降低架構(gòu)微服務(wù)化的成本盯质,提高調(diào)用方與服務(wù)提供方的研發(fā)效率袁串。

2、RPC 框架的技術(shù)架構(gòu)

如下圖呼巷,在典型 RPC 的使用場(chǎng)景中囱修,主要包含了服務(wù)發(fā)現(xiàn)、負(fù)載王悍、容錯(cuò)破镰、網(wǎng)絡(luò)傳輸、序列化等組件,其中 ”RPC協(xié)議”就指明了服務(wù)如何進(jìn)行序列化和網(wǎng)絡(luò)傳輸鲜漩,這也是RPC的核心功能源譬。

  • 應(yīng)用級(jí)的RPC框架:Dubbo、Google gRPC
  • 通信框架:Netty
  • 遠(yuǎn)程通信協(xié)議:RMI孕似、Socket踩娘、SOAP(HTTP XML)、REST(HTTP JSON)
image.png

3喉祭、RPC 框架的調(diào)用流程

image.png

3.1养渴、RPC 框架的核心組件:

(1)客戶端(Client):服務(wù)調(diào)用方。

(2)客戶端存根(Client Stub):存放服務(wù)端地址信息泛烙,將客戶端的請(qǐng)求參數(shù)數(shù)據(jù)信息打包成網(wǎng)絡(luò)消息理卑,再通過(guò)網(wǎng)絡(luò)傳輸發(fā)送給服務(wù)端。

(3)服務(wù)端存根(Server Stub):接收客戶端發(fā)送過(guò)來(lái)的請(qǐng)求消息并進(jìn)行解包蔽氨,然后再調(diào)用本地服務(wù)進(jìn)行處理藐唠。

(4)服務(wù)端(Server):服務(wù)的真正提供者。

3.2孵滞、RPC 的調(diào)用流程:

(1)服務(wù)消費(fèi)者(Client 客戶端)通過(guò)本地調(diào)用的方式調(diào)用需要消費(fèi)的服務(wù)

(2)客戶端存根(Client Stub)接收到調(diào)用請(qǐng)求后負(fù)責(zé)將方法中捆、入?yún)⒌刃畔⑿蛄谢ńM裝)成能夠進(jìn)行網(wǎng)絡(luò)傳輸?shù)南Ⅲw

(3)客戶端存根(Client Stub)找到遠(yuǎn)程的服務(wù)地址,并且將消息通過(guò)網(wǎng)絡(luò)發(fā)送給服務(wù)端

(4)服務(wù)端存根(Server Stub)收到消息后進(jìn)行解碼坊饶,反序列化操作

(5)服務(wù)端存根(Server Stub)根據(jù)解碼結(jié)果調(diào)用本地的服務(wù)進(jìn)行相關(guān)處理

(6)服務(wù)端(Server)執(zhí)行具體的業(yè)務(wù)邏輯泄伪,并將處理結(jié)果返回給服務(wù)端存根(Server Stub)

(7)服務(wù)端存根(Server Stub)將返回結(jié)果序列化,并通過(guò)網(wǎng)絡(luò)發(fā)送給消費(fèi)方

(8)客戶端存根(Client Stub)接收到消息匿级,并進(jìn)行解碼與反序列化

(9)服務(wù)消費(fèi)方得到最終結(jié)果蟋滴;

而RPC框架的實(shí)現(xiàn)目標(biāo)則是將上面的<typo id="typo-2298" data-origin="得到" ignoretag="true">第2</typo>-10步完好地封裝起來(lái),也就是把調(diào)用痘绎、編碼/解碼的過(guò)程給封裝起來(lái)津函,讓用戶感覺(jué)上像調(diào)用本地服務(wù)一樣的調(diào)用遠(yuǎn)程服務(wù)

image.png

4、如何實(shí)現(xiàn)一個(gè)RPC框架孤页?

通過(guò)上面幾點(diǎn)的介紹尔苦,如果要我們實(shí)現(xiàn)一個(gè) RPC 框架,我們應(yīng)該如果做呢行施?要實(shí)現(xiàn) 一個(gè)RPC 框架允坚,我們只需要解決的以下幾件最基本的事情:

4.1、如何進(jìn)行網(wǎng)絡(luò)通訊蛾号?

遠(yuǎn)程調(diào)用中稠项,客戶端和服務(wù)端的通訊是基于網(wǎng)絡(luò)連接的,所以首先需要建立通信連接鲜结,通過(guò)這個(gè)連接把請(qǐng)求信息的字節(jié)流傳給服務(wù)端展运,然后再把序列化后的響應(yīng)結(jié)果傳回客戶端活逆,在這個(gè)通訊過(guò)程中,它所使用的協(xié)議是沒(méi)有限制的拗胜,能完成傳輸就行蔗候,但是在這里我們需要考慮兩個(gè)問(wèn)題:如何選擇網(wǎng)絡(luò)協(xié)議 和 如何建立連接。

(1)網(wǎng)絡(luò)協(xié)議的選擇:多數(shù) RPC 框架選擇 TCP 作為傳輸協(xié)議挤土,但其實(shí) UDP 也可以琴庵,也有部分選擇HTTP,比如 gRPC 使用 HTTP2仰美,但是不同的協(xié)議各有優(yōu)劣勢(shì)迷殿,TCP 更加高效,而 HTTP 在實(shí)際應(yīng)用中更加的靈活咖杂,具體需要根據(jù)使用場(chǎng)景來(lái)選擇庆寺,下文會(huì)介紹如何選擇正確的網(wǎng)絡(luò)傳輸協(xié)議

(2)通訊連接的建立:RPC 所有交換的數(shù)據(jù)都在這個(gè)連接里傳輸,這個(gè)連接可以是按需連接(需要調(diào)用時(shí)就先建立連接诉字,調(diào)用結(jié)束后就立馬斷掉)懦尝,也可以是長(zhǎng)連接(客戶端和服務(wù)器建立起連接之后保持長(zhǎng)期持有,不管此時(shí)有無(wú)數(shù)據(jù)包的發(fā)送壤圃,可以配合心跳檢測(cè)機(jī)制定期檢測(cè)建立的連接是否存活有效)陵霉,多個(gè)遠(yuǎn)程過(guò)程調(diào)用共享同一個(gè)連接。

4.2伍绳、如何那行服務(wù)尋址踊挠?

解決尋址的問(wèn)題,也就是說(shuō)服務(wù)端如何確定客戶端要調(diào)用的函數(shù)冲杀,在本地調(diào)用中效床,函數(shù)是直接通過(guò)函數(shù)指針來(lái)指定的,但是在遠(yuǎn)程調(diào)用中权谁,函數(shù)指針是不行的剩檀,因?yàn)閮蓚€(gè)進(jìn)程的地址空間是完全不一樣的。所以在遠(yuǎn)程調(diào)用中旺芽,客戶端和服務(wù)端需要分別維護(hù)一個(gè)【ID -> 函數(shù)】的映射表沪猴,ID在所有進(jìn)程中都是唯一確定的,客戶端在做遠(yuǎn)程過(guò)程調(diào)用時(shí)采章,附上這個(gè)ID运嗜,服務(wù)端通過(guò)查表,來(lái)確定客戶端需要調(diào)用的函數(shù)共缕,然后執(zhí)行相應(yīng)函數(shù)的代碼。

而尋址問(wèn)題的具體實(shí)現(xiàn)方式士复,則可以通過(guò)注冊(cè)中心图谷,服務(wù)提供者完成后翩活,對(duì)外暴露相應(yīng)的功能并將自己注冊(cè)到注冊(cè)中心上,接著服務(wù)消費(fèi)者從注冊(cè)中心尋找服務(wù)便贵,然后調(diào)用該服務(wù)對(duì)應(yīng)的方法完成遠(yuǎn)程調(diào)用

(1)從服務(wù)提供者的角度看:

當(dāng)服務(wù)提供者啟動(dòng)的時(shí)候菠镇,需要將自己提供的服務(wù)注冊(cè)到指定的注冊(cè)中心,以便服務(wù)消費(fèi)者能夠通過(guò)服務(wù)注冊(cè)中心進(jìn)行查找承璃;

當(dāng)服務(wù)提供者由于各種原因致使提供的服務(wù)停止時(shí)利耍,需要向注冊(cè)中心注銷(xiāo)停止的服務(wù);服務(wù)的提供者需要定期向服務(wù)注冊(cè)中心發(fā)送心跳檢測(cè)盔粹,服務(wù)注冊(cè)中心如果一段時(shí)間未收到來(lái)自服務(wù)提供者的心跳后隘梨,認(rèn)為該服務(wù)提供者已經(jīng)停止服務(wù),則將該服務(wù)從注冊(cè)中心上去掉舷嗡。

(2)從調(diào)用者的角度看:

服務(wù)的調(diào)用者啟動(dòng)的時(shí)候根據(jù)自己訂閱的服務(wù)向服務(wù)注冊(cè)中心查找服務(wù)提供者的地址等信息轴猎;

當(dāng)服務(wù)調(diào)用者消費(fèi)的服務(wù)上線或者下線的時(shí)候,注冊(cè)中心會(huì)告知該服務(wù)的調(diào)用者进萄;

服務(wù)調(diào)用者下線的時(shí)候捻脖,則取消訂閱。

4.3中鼠、如何序列化和反序列化可婶?

在本地調(diào)用中,我們只需要把參數(shù)信息壓到內(nèi)存棧中援雇,然后讓函數(shù)自己去棧中讀取矛渴,但是遠(yuǎn)程過(guò)程調(diào)用時(shí),客戶端跟服務(wù)端是不同的進(jìn)程熊杨,不能通過(guò)內(nèi)存來(lái)傳遞參數(shù)曙旭。所以遠(yuǎn)程過(guò)程調(diào)用中,客戶端和服務(wù)端交互時(shí)晶府,方法的參數(shù)和結(jié)果需要通過(guò)底層的網(wǎng)絡(luò)協(xié)議如TCP傳遞桂躏,由于網(wǎng)絡(luò)協(xié)議是基于二進(jìn)制的(只有二進(jìn)制數(shù)據(jù)才能在網(wǎng)絡(luò)中傳輸),那么這些值需要序列化成二進(jìn)制的形式川陆,通過(guò)尋址和傳輸將序列化的二進(jìn)制發(fā)送目標(biāo)服務(wù)器剂习。目標(biāo)服務(wù)器接收到數(shù)據(jù)時(shí),需要對(duì)數(shù)據(jù)進(jìn)行反序列化较沪。序列化和反序列化的速度也會(huì)影響遠(yuǎn)程調(diào)用的效率鳞绕。

  • 將對(duì)象轉(zhuǎn)換成二進(jìn)制流的過(guò)程叫做序列化
  • 將二進(jìn)制流轉(zhuǎn)換成對(duì)象的過(guò)程叫做反序列化

5、如何選擇正確的PRC網(wǎng)絡(luò)傳輸協(xié)議尸曼?

在 RPC 中可選的網(wǎng)絡(luò)傳輸方式有多種们何,比如 TCP 協(xié)議、UDP 協(xié)議控轿、HTTP 協(xié)議冤竹。每一種協(xié)議對(duì)整體的性能和效率都有不同的影響拂封,那如何選擇一個(gè)正確的網(wǎng)絡(luò)傳輸協(xié)議呢?針對(duì)這個(gè)問(wèn)題鹦蠕,我們首先要搞明白各種傳輸協(xié)議在 RPC 中的工作方式:

  • 基于 TCP 的協(xié)議實(shí)現(xiàn)的 RPC 調(diào)用冒签,由于 TCP 協(xié)議處于協(xié)議棧的下層,能夠更加靈活地對(duì)協(xié)議字段進(jìn)行定制钟病,讓請(qǐng)求報(bào)文體積更小萧恕,減少網(wǎng)絡(luò)開(kāi)銷(xiāo),提高傳輸性能并縮短傳輸耗時(shí)肠阱,實(shí)現(xiàn)更大的吞吐量和并發(fā)數(shù)票唆。但是需要更多關(guān)注底層復(fù)雜的細(xì)節(jié),實(shí)現(xiàn)的代價(jià)更高辖所,同時(shí)對(duì)不同平臺(tái)惰说,如安卓,iOS 等缘回,需要重新開(kāi)發(fā)出不同的工具包來(lái)進(jìn)行請(qǐng)求發(fā)送和相應(yīng)解析吆视,工作量大,難以快速響應(yīng)和滿足用戶需求酥宴。
  • 基于 HTTP 協(xié)議實(shí)現(xiàn)的 RPC 則可以使用 JSON 和 XML 格式的請(qǐng)求或響應(yīng)數(shù)據(jù)啦吧,而 JSON 和 XML 作為通用的格式標(biāo)準(zhǔn)(使用 HTTP 協(xié)議也需要序列化和反序列化,不過(guò)這不是該協(xié)議下關(guān)心的內(nèi)容拙寡,成熟的 Web 程序已經(jīng)做好了序列化內(nèi)容)授滓,開(kāi)源的解析工具已經(jīng)相當(dāng)成熟,在其上進(jìn)行二次開(kāi)發(fā)會(huì)非常便捷和簡(jiǎn)單肆糕。但是由于 HTTP 協(xié)議是上層協(xié)議般堆,發(fā)送包含同等內(nèi)容的信息,請(qǐng)求中會(huì)包含很多無(wú)用的內(nèi)容诚啃,所占用的字節(jié)數(shù)比使用 TCP 協(xié)議傳輸更高淮摔,因此在同等網(wǎng)絡(luò)下,HTTP 會(huì)比基于 TCP 協(xié)議的數(shù)據(jù)傳輸效率要低始赎,傳輸耗時(shí)更長(zhǎng)和橙,當(dāng)然壓縮數(shù)據(jù),能夠縮小這一差距造垛。

三魔招、RPC框架dubbo

1、dubbo 是什么五辽?

前面講到办斑,RPC 常用于微服務(wù)架構(gòu)中,而 RPC 框架作為架構(gòu)微服務(wù)化的基礎(chǔ)組件杆逗,能大大降低架構(gòu)微服務(wù)化的成本乡翅,提高調(diào)用方與服務(wù)提供方的研發(fā)效率吁讨。而 Dubbo 是阿里巴巴開(kāi)源的基于 Java 的 RPC 分布式服務(wù)框架,提供高性能和透明化的 RPC 遠(yuǎn)程服務(wù)調(diào)用方案峦朗,以及 SOA 服務(wù)治理方案。另外排龄,基于 Spring Cloud Alibaba 技術(shù)棧的 Spring-cloud-alibaba-dubbo 更是對(duì) dubbo 技術(shù)進(jìn)行了封裝波势,在基于 Spring Cloud Alibaba 提供的 Nacos 注冊(cè)中心下,提供了 Dubbo 和 Spring Cloud 的整合方案橄维,即 Dubbo Spring Cloud尺铣,使得服務(wù)內(nèi)部的 RPC 協(xié)議調(diào)用幾乎是零成本的改造,實(shí)現(xiàn)了基于 RPC 的服務(wù)調(diào)用争舞。

2凛忿、dubbo 的執(zhí)行流程

2.1、dubbo 總體流程:

image.png
  • 紫色虛線:?jiǎn)?dòng)時(shí)完成的功能
  • 藍(lán)色虛線:運(yùn)行過(guò)程中執(zhí)行的功能竞川,異步調(diào)用
  • 藍(lán)色實(shí)線:運(yùn)行過(guò)程中執(zhí)行的功能店溢,同步調(diào)用

2.1.1、dubbo 的總體執(zhí)行流程說(shuō)明如下:

(1)啟動(dòng)容器委乌,加載床牧,運(yùn)行服務(wù)提供者。

(2)服務(wù)提供者在啟動(dòng)時(shí)遭贸,向注冊(cè)中心注冊(cè)自己提供的服務(wù)戈咳。

(3)服務(wù)消費(fèi)者在啟動(dòng)時(shí),向注冊(cè)中心訂閱自己所需的服務(wù)壕吹。

(4)注冊(cè)中心返回服務(wù)提供者地址列表給消費(fèi)者著蛙,消費(fèi)者接收到之后,緩存在本地中耳贬,如果內(nèi)容有變更踏堡,注冊(cè)中心將基于長(zhǎng)連接推送變更數(shù)據(jù)給消費(fèi)者。

(5)服務(wù)消費(fèi)者效拭,從提供者地址列表中暂吉,基于軟負(fù)載均衡算法,選擇一臺(tái)提供者進(jìn)行調(diào)用缎患,如果調(diào)用失敗慕的,再選另一臺(tái)調(diào)用。

(6)服務(wù)消費(fèi)者和提供者挤渔,在內(nèi)存中累計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間肮街,定時(shí)每分鐘發(fā)送一次統(tǒng)計(jì)數(shù)據(jù)到監(jiān)控中心。

在consumer中使用了代理模式判导,創(chuàng)建了一個(gè)Provider類的一個(gè)代理對(duì)象嫉父。通過(guò)代理對(duì)象獲取Provider中的真實(shí)功能沛硅,起到保護(hù)Provider真實(shí)功能的作用。

2.1.2绕辖、dubbo 的整個(gè)執(zhí)行流程可以理解為生產(chǎn)者-消費(fèi)者模型+注冊(cè)中心+監(jiān)控中心摇肌,這樣設(shè)計(jì)的原因在于:

  • Consumer 與 Provider 解偶,雙方都可以橫向增減節(jié)點(diǎn)數(shù)
  • 注冊(cè)中心對(duì)本身可做對(duì)等集群仪际,可動(dòng)態(tài)增減節(jié)點(diǎn)围小,并且任意一臺(tái)宕掉后,將自動(dòng)切換到另一臺(tái)
  • 去中心化树碱,雙方不直接依懶注冊(cè)中心肯适,即使注冊(cè)中心全部宕機(jī)短時(shí)間內(nèi)也不會(huì)影響服務(wù)的調(diào)用
  • 服務(wù)提供者無(wú)狀態(tài),任意一臺(tái)宕掉后成榜,不影響使用

2.2框舔、dubbo 同步調(diào)用原理

2.2.1、dubbo 同步調(diào)用流程:

(1)客戶端線程調(diào)用遠(yuǎn)程接口赎婚,向服務(wù)端發(fā)送請(qǐng)求刘绣,同時(shí)當(dāng)前線程應(yīng)該處于“暫停“狀態(tài)挣输,即線程不能向后執(zhí)行了额港,必需要拿到服務(wù)端給自己的結(jié)果后才能向后執(zhí)行

(2)服務(wù)端接到客戶端請(qǐng)求后,處理請(qǐng)求歧焦,將結(jié)果給客戶端

(3)客戶端收到結(jié)果移斩,然后當(dāng)前線程繼續(xù)往后執(zhí)行

dubbo 中使用了 Socket 來(lái)建立長(zhǎng)連接、數(shù)據(jù)傳輸绢馍,而底層結(jié)合了的 Apache mina 框架向瓷,Apache mina 框架基于Reactor模型通信框架,基于tcp長(zhǎng)連接舰涌。dubbo 使用 IoSession.write() 方法進(jìn)行遠(yuǎn)程調(diào)用與發(fā)送消息猖任,這個(gè)方法的遠(yuǎn)程調(diào)用過(guò)程異步的,即對(duì)于當(dāng)前線程來(lái)說(shuō)瓷耙,將請(qǐng)求發(fā)送出來(lái)朱躺,線程就可以往后執(zhí)行了,至于服務(wù)端的結(jié)果搁痛,是服務(wù)端處理完成后长搀,再以消息的形式發(fā)送給客戶端的。于是這里出現(xiàn)了2個(gè)問(wèn)題:

(1)當(dāng)前線程怎么讓它“暫图Φ洌”源请,等結(jié)果回來(lái)后,再向后執(zhí)行:

先生成一個(gè)對(duì)象 obj,在一個(gè)全局 map 里 put(ID,obj) 存放起來(lái)谁尸,再用 synchronized 獲取 obj 鎖舅踪,再調(diào)用 obj.wait() 讓當(dāng)前線程處于等待狀態(tài),然后另一消息監(jiān)聽(tīng)線程等到服務(wù)端處理結(jié)果到來(lái)良蛮,再 map.get(ID) 找到 obj抽碌,再用 synchronized 獲取obj鎖,再調(diào)用 obj.notifyAll() 喚醒前面處于等待狀態(tài)的線程决瞳。

(2)Socket通信是一個(gè)全雙工的方式咬展,當(dāng)有多個(gè)線程同時(shí)進(jìn)行遠(yuǎn)程方法調(diào)用,這時(shí) client 與 server 間的 socket 連接上會(huì)有很多雙方發(fā)送的消息傳遞瞒斩,前后順序也可能是亂七八糟的,server處理完結(jié)果后涮总,將結(jié)果消息發(fā)送給client胸囱,client收到很多消息,怎么知道哪個(gè)消息結(jié)果是原先哪個(gè)線程調(diào)用的:

使用一個(gè)ID瀑梗,讓其唯一烹笔,然后傳遞給服務(wù)端,再服務(wù)端又回傳回來(lái)抛丽,這樣就知道結(jié)果是原先哪個(gè)線程的了

2.2.2谤职、dubbo同步調(diào)用原理:

(1)客戶端使用一個(gè)線程調(diào)用遠(yuǎn)程接口,生成一個(gè)唯一 ID亿鲜,Dubbo 是使用 AtomicLong 從 0 開(kāi)始累計(jì)數(shù)字的

(2)將打包的方法調(diào)用信息(如調(diào)用的接口名稱允蜈,方法名稱,參數(shù)值列表等)蒿柳,和處理結(jié)果的回調(diào)對(duì)象callback饶套,全部封裝在一起,組成一個(gè)對(duì)象object

(3)向?qū)iT(mén)存放調(diào)用信息的全局 ConcurrentHashMap 里面 put(ID, object)

(4)將 ID 和打包的方法調(diào)用信息封裝成一對(duì)象 connRequest垒探,使用 IoSession.write(connRequest) 異步發(fā)送出去

(5)當(dāng)前線程再使用 callback 的 get() 方法試圖獲取遠(yuǎn)程返回的結(jié)果妓蛮,在get()內(nèi)部,則先使用synchronized獲取回調(diào)對(duì)象callback的鎖圾叼, 檢測(cè)是否已經(jīng)獲取到結(jié)果蛤克,如果沒(méi)有,然后調(diào)用 callback 的 wait() 方法夷蚊,釋放 callback 上的鎖构挤,讓當(dāng)前線程處于等待狀態(tài)。

(6)服務(wù)端接收到請(qǐng)求并處理后惕鼓,將結(jié)果(包含了唯一ID)回傳給客戶端儿倒,客戶端 socket 連接上專門(mén)監(jiān)聽(tīng)消息的線程收到消息后,分析結(jié)果,取到ID夫否,再?gòu)那懊娴?ConcurrentHashMap 里面 get(ID)彻犁,從而找到 callback,將方法調(diào)用結(jié)果設(shè)置到callback對(duì)象里凰慈。

(7)最后監(jiān)聽(tīng)線程再獲取回調(diào)對(duì)象 callback 的 synchronized 鎖(因?yàn)榍懊嬲{(diào)用過(guò)wait() 導(dǎo)致釋放callback的鎖)汞幢,先使用 notifyAll() 喚醒前面處于等待狀態(tài)的線程繼續(xù)執(zhí)行,這樣 callback 的 get( )方法繼續(xù)執(zhí)行就能拿到調(diào)用結(jié)果了微谓,至此森篷,整個(gè)過(guò)程結(jié)束

需要注意的是,這里的callback對(duì)象是每次調(diào)用產(chǎn)生一個(gè)新的豺型,不能共享仲智;另外ID必需至少保證在一個(gè)Socket連接里面是唯一的。

3姻氨、dubbo 的負(fù)載均衡策略

(1)隨機(jī)調(diào)用策略(默認(rèn)):隨機(jī)選擇服務(wù)器節(jié)點(diǎn)钓辆,該策略可以對(duì)不同服務(wù)器實(shí)例設(shè)置不同的權(quán)重,權(quán)重越大分配流量越高

(2)輪詢調(diào)用策略:均勻地將請(qǐng)求分配到各個(gè)機(jī)器上肴焊。如果各個(gè)機(jī)器的性能不一樣前联,容易導(dǎo)致性能差的機(jī)器負(fù)載過(guò)高,所以此時(shí)需要調(diào)整權(quán)重娶眷,讓性能差的機(jī)器承載權(quán)重小一些似嗤,流量少一些。

(3)最少活躍數(shù)策略:根據(jù)服務(wù)器的運(yùn)行狀態(tài)去選擇服務(wù)届宠,如果某個(gè)機(jī)器性能越差烁落,那么接收的請(qǐng)求越少,越不活躍豌注,此時(shí)就會(huì)給不活躍的性能差的機(jī)器分配更少的請(qǐng)求

(4)一致性哈希算法:相同參數(shù)的請(qǐng)求一定會(huì)被分發(fā)到固定的服務(wù)器節(jié)點(diǎn)顽馋。當(dāng)某個(gè)服務(wù)器節(jié)點(diǎn)掛掉的時(shí)候,會(huì)基于虛擬節(jié)點(diǎn)均勻分配剩余的流量幌羞,抖動(dòng)不會(huì)太大寸谜。

4、dubbo 的容錯(cuò)機(jī)制

Failover(默認(rèn)):失敗自動(dòng)切換属桦,當(dāng)出現(xiàn)失敗熊痴,重試其它服務(wù)器,默認(rèn)為2次聂宾。通常用于讀操作果善,但重試會(huì)帶來(lái)更長(zhǎng)延遲。

Failfast:快速失敗系谐,只發(fā)起一次調(diào)用巾陕,失敗立即報(bào)錯(cuò)讨跟。通常用于非冪等性的寫(xiě)操作,比如新增記錄鄙煤。

Failsafe:失敗安全晾匠,出現(xiàn)異常時(shí),直接忽略梯刚。通常用于寫(xiě)入審計(jì)日志等操作凉馆。

Failback:失敗自動(dòng)恢復(fù),后臺(tái)記錄失敗請(qǐng)求亡资,定時(shí)重發(fā)澜共。通常用于消息通知操作。

Forking:并行調(diào)用多個(gè)服務(wù)器锥腻,只要一個(gè)成功即返回嗦董。通常用于實(shí)時(shí)性要求較高的讀操作,但需要浪費(fèi)更多服務(wù)資源瘦黑【└铮可通過(guò) forks=”2″ 來(lái)設(shè)置最大并行數(shù)。

Broadcast:廣播調(diào)用所有提供者供璧,逐個(gè)調(diào)用,任意一臺(tái)報(bào)錯(cuò)則報(bào)錯(cuò) 冻记。通常用于通知所有提供者更新緩存或日志等本地資源信息睡毒。

5、dubbo支持哪些協(xié)議和適用場(chǎng)景冗栗?

(1)dubbo:?jiǎn)我婚L(zhǎng)連接和 NIO 異步通訊演顾,適合大并發(fā)小數(shù)據(jù)量的服務(wù)調(diào)用,以及消費(fèi)者遠(yuǎn)大于提供者的情況隅居。傳輸協(xié)議 TCP钠至,異步 Hessian 序列化。Dubbo 官方推薦使用 dubbo 協(xié)議胎源。但是棉钧,dubbo 協(xié)議不適合傳送大數(shù)據(jù)量的服務(wù),比如傳文件涕蚤,傳視頻等宪卿,除非請(qǐng)求量很低

(2)RMI: 采用 JDK 標(biāo)準(zhǔn)的 RMI 協(xié)議實(shí)現(xiàn),使用 Java 標(biāo)準(zhǔn)序列化機(jī)制万栅,傳輸參數(shù)和返回參數(shù)對(duì)象需要實(shí)現(xiàn) Serializable 接口佑钾,使用阻塞式短連接,傳輸數(shù)據(jù)包大小混合烦粒,消費(fèi)者和提供者個(gè)數(shù)差不多休溶,可傳文件,傳輸協(xié)議 TCP。多個(gè)短連接兽掰,基于 TCP 協(xié)議傳輸芭碍,同步傳輸,適用常規(guī)的遠(yuǎn)程服務(wù)調(diào)用和 RMI 互操作禾进。在依賴低版本的 Common-Collections 包豁跑,Java 序列化存在安全漏洞。

(3)WebService:基于 WebService 的遠(yuǎn)程調(diào)用協(xié)議泻云,集成 CXF 實(shí)現(xiàn)艇拍,提供和原生 WebService 的互操作。多個(gè)短連接宠纯,基于 HTTP 傳輸卸夕,同步傳輸,適用系統(tǒng)集成和跨語(yǔ)言調(diào)用婆瓜。

(4)HTTP: 基于 Http 表單提交的遠(yuǎn)程調(diào)用協(xié)議快集,使用 Spring 的 HttpInvoke 實(shí)現(xiàn)。多個(gè)短連接廉白,傳輸協(xié)議 HTTP个初,傳入?yún)?shù)大小混合,提供者個(gè)數(shù)多于消費(fèi)者猴蹂,需要給應(yīng)用程序和瀏覽器 JS 調(diào)用院溺。

(5)Hessian:集成 Hessian 服務(wù),基于 HTTP 通訊磅轻,采用 Servlet 暴露服務(wù)珍逸,Dubbo 內(nèi)嵌 Jetty 作為服務(wù)器時(shí)默認(rèn)實(shí)現(xiàn),提供與 Hession 服務(wù)互操作聋溜。多個(gè)短連接谆膳,同步 HTTP 傳輸,Hessian 序列化撮躁,傳入?yún)?shù)較大漱病,提供者大于消費(fèi)者,提供者壓力較大把曼,可傳文件缨称。

(6)Redis:基于 Redis 實(shí)現(xiàn)的RPC協(xié)議。

(7)Memcache:基于 Memcache實(shí)現(xiàn)的 RPC 協(xié)議祝迂。

6睦尽、dubbo 的通信框架:

dubbo 默認(rèn)使用 Netty 作為通訊框架

7、dubbo的架構(gòu)設(shè)計(jì):

image.png

7.1型雳、圖例說(shuō)明

  • 左邊淡藍(lán)背景的為服務(wù)消費(fèi)方使用的接口当凡,右邊淡綠色背景的為服務(wù)提供方使用的接口山害,位于中軸線上的為雙方都用到的接口。
  • 圖中從下至上分為 10 層沿量,各層均為單向依賴浪慌,右邊的黑色箭頭代表層之間的依賴關(guān)系,每一層都可以剝離上層被復(fù)用朴则,其中权纤,Service 和 Config 層為 API,其它各層均為 SPI乌妒。
  • 圖中綠色小塊的為擴(kuò)展接口汹想,藍(lán)色小塊為實(shí)現(xiàn)類,圖中只顯示用于關(guān)聯(lián)各層的實(shí)現(xiàn)類撤蚊。
  • 圖中藍(lán)色虛線為初始化過(guò)程古掏,即啟動(dòng)時(shí)組裝鏈,紅色實(shí)線為方法調(diào)用過(guò)程侦啸,即運(yùn)行時(shí)調(diào)時(shí)鏈槽唾,紫色三角箭頭為繼承,可以把子類看作父類的同一個(gè)節(jié)點(diǎn)光涂,線上的文字為調(diào)用的方法庞萍。

7.2、各層說(shuō)明:

(1)接口服務(wù)層(Service):該層與實(shí)際業(yè)務(wù)邏輯相關(guān)忘闻,根據(jù) provider 和 consumer 的業(yè)務(wù)設(shè)計(jì)對(duì)應(yīng)的接口和實(shí)現(xiàn)

(2)配置層(Config):對(duì)外配置接口钝计,以 ServiceConfig 和 ReferenceConfig 為中心

(3)服務(wù)代理層(Proxy):服務(wù)接口透明代理,生成服務(wù)的客戶端 Stub 和 服務(wù)端的 Skeleton服赎,以 ServiceProxy 為中心葵蒂,擴(kuò)展接口為 ProxyFactory

(4)服務(wù)注冊(cè)層(Registry):封裝服務(wù)地址的注冊(cè)和發(fā)現(xiàn)交播,以服務(wù) URL 為中心重虑,擴(kuò)展接口為 RegistryFactory、Registry秦士、RegistryService

(5)路由層(Cluster):封裝多個(gè)提供者的路由和負(fù)載均衡缺厉,并橋接注冊(cè)中心,以Invoker 為中心隧土,擴(kuò)展接口為 Cluster提针、Directory、Router 和 LoadBlancce

(6)監(jiān)控層(Monitor):RPC 調(diào)用次數(shù)和調(diào)用時(shí)間監(jiān)控曹傀,以 Statistics 為中心辐脖,擴(kuò)展接口為 MonitorFactory、Monitor 和 MonitorService

(7)遠(yuǎn)程調(diào)用層(Protocal):封裝 RPC 調(diào)用皆愉,以 Invocation 和 Result 為中心嗜价,擴(kuò)展接口為 Protocal艇抠、Invoker 和 Exporter

(8)信息交換層(Exchange):封裝請(qǐng)求響應(yīng)模式,同步轉(zhuǎn)異步久锥。以 Request 和Response 為中心家淤,擴(kuò)展接口為 Exchanger、ExchangeChannel瑟由、ExchangeClient 和 ExchangeServer

(9)網(wǎng)絡(luò) 傳輸 層(Transport):抽象 mina 和 netty 為統(tǒng)一接口絮重,以 Message 為中心,擴(kuò)展接口為 Channel歹苦、Transporter青伤、Client、Server 和 Codec

(10)數(shù)據(jù)序列化層(Serialize):可復(fù)用的一些工具暂氯,擴(kuò)展接口為 Serialization潮模、ObjectInput、ObjectOutput 和 ThreadPool

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痴施,一起剝皮案震驚了整個(gè)濱河市擎厢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辣吃,老刑警劉巖动遭,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異神得,居然都是意外死亡厘惦,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)哩簿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宵蕉,“玉大人,你說(shuō)我怎么就攤上這事节榜∠勐辏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵宗苍,是天一觀的道長(zhǎng)稼稿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)讳窟,這世上最難降的妖魔是什么让歼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮丽啡,結(jié)果婚禮上谋右,老公的妹妹穿的比我還像新娘。我一直安慰自己补箍,他們只是感情好改执,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布浦徊。 她就那樣靜靜地躺著,像睡著了一般天梧。 火紅的嫁衣襯著肌膚如雪盔性。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天呢岗,我揣著相機(jī)與錄音冕香,去河邊找鬼。 笑死后豫,一個(gè)胖子當(dāng)著我的面吹牛悉尾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挫酿,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼构眯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了早龟?” 一聲冷哼從身側(cè)響起惫霸,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎葱弟,沒(méi)想到半個(gè)月后壹店,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芝加,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年硅卢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藏杖。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡将塑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝌麸,到底是詐尸還是另有隱情点寥,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布祥楣,位于F島的核電站开财,受9級(jí)特大地震影響汉柒,放射性物質(zhì)發(fā)生泄漏误褪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一碾褂、第九天 我趴在偏房一處隱蔽的房頂上張望兽间。 院中可真熱鬧,春花似錦正塌、人聲如沸嘀略。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)帜羊。三九已至咒程,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讼育,已是汗流浹背帐姻。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奶段,地道東北人饥瓷。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像痹籍,于是被迫代替她去往敵國(guó)和親呢铆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容