本文轉(zhuǎn)自 https://developer.51cto.com/art/201906/597963.htm
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),翼城企業(yè)網(wǎng)站建設(shè),翼城品牌網(wǎng)站建設(shè),網(wǎng)站定制,翼城網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,翼城網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
RPC(Remote Procedure Call):遠(yuǎn)程過(guò)程調(diào)用,它是一種通過(guò)網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請(qǐng)求服務(wù),而不需要了解底層網(wǎng)絡(luò)技術(shù)的思想。
RPC 是一種技術(shù)思想而非一種規(guī)范或協(xié)議,常見 RPC 技術(shù)和框架有:
目前流行的開源 RPC 框架還是比較多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。
在一個(gè)典型 RPC 的使用場(chǎng)景中,包含了服務(wù)發(fā)現(xiàn)、負(fù)載、容錯(cuò)、網(wǎng)絡(luò)傳輸、序列化等組件,其中“RPC 協(xié)議”就指明了程序如何進(jìn)行網(wǎng)絡(luò)傳輸和序列化。
圖 1:完整 RPC 架構(gòu)圖
如下是 Dubbo 的設(shè)計(jì)架構(gòu)圖,分層清晰,功能復(fù)雜:
圖 2:Dubbo 架構(gòu)圖
RPC 核心功能
RPC 的核心功能是指實(shí)現(xiàn)一個(gè) RPC 最重要的功能模塊,就是上圖中的”RPC 協(xié)議”部分:
圖 3:RPC 核心功能
一個(gè) RPC 的核心功能主要有 5 個(gè)部分組成,分別是:客戶端、客戶端 Stub、網(wǎng)絡(luò)傳輸模塊、服務(wù)端 Stub、服務(wù)端等。
圖 4:RPC 核心功能圖
下面分別介紹核心 RPC 框架的重要組成:
Server.py:
fromSimpleXMLRPCServer importSimpleXMLRPCServer
deffun_add(a,b):
totle = a + b
returntotle
if__name__ == '__main__':
s = SimpleXMLRPCServer(( '0.0.0.0', 8080)) #開啟xmlrpcserver
s.register_function(fun_add) #注冊(cè)函數(shù)fun_add
print"server is online..."
s.serve_forever #開啟循環(huán)等待
Client.py:
fromxmlrpclib importServerProxy #導(dǎo)入xmlrpclib的包
s = ServerProxy( "http://172.171.5.205:8080") #定義xmlrpc客戶端
prints.fun_add( 2, 3) #調(diào)用服務(wù)器端的函數(shù)
開啟服務(wù)端:
開啟客戶端:
Wireshark 抓包分析過(guò)程
客戶端去往服務(wù)端:
通信使用 HTTP 協(xié)議,XML 文件傳輸格式。傳輸?shù)淖侄伟ǎ悍椒?methodName,兩個(gè)參數(shù) 2,3。
圖 5:Request 抓包
服務(wù)端返回結(jié)果,字段返回值 Value,結(jié)果是 5:
圖 6:Response 抓包
在這兩次網(wǎng)絡(luò)傳輸中使用了 HTTP 協(xié)議,建立 HTTP 協(xié)議之間有 TCP 三次握手,斷開 HTTP 協(xié)議時(shí)有 TCP 四次揮手。
圖 7:基于 HTTP 協(xié)議的 RPC 連接過(guò)程
詳細(xì)調(diào)用過(guò)程
Python 自帶 RPC 的 Demo 小程序的實(shí)現(xiàn)過(guò)程,流程和分工角色可以用下圖來(lái)表示:
圖 8:RPC 調(diào)用詳細(xì)流程圖
一次 RPC 調(diào)用流程如下:
RPC 的核心功能主要由 5 個(gè)模塊組成,如果想要自己實(shí)現(xiàn)一個(gè) RPC,最簡(jiǎn)單的方式要實(shí)現(xiàn)三個(gè)技術(shù)點(diǎn),分別是:
服務(wù)尋址可以使用 Call ID 映射。在本地調(diào)用中,函數(shù)體是直接通過(guò)函數(shù)指針來(lái)指定的,但是在遠(yuǎn)程調(diào)用中,函數(shù)指針是不行的,因?yàn)閮蓚€(gè)進(jìn)程的地址空間是完全不一樣的。
所以在 RPC 中,所有的函數(shù)都必須有自己的一個(gè) ID。這個(gè) ID 在所有進(jìn)程中都是唯一確定的。
客戶端在做遠(yuǎn)程過(guò)程調(diào)用時(shí),必須附上這個(gè) ID。然后我們還需要在客戶端和服務(wù)端分別維護(hù)一個(gè)函數(shù)和Call ID的對(duì)應(yīng)表。
當(dāng)客戶端需要進(jìn)行遠(yuǎn)程調(diào)用時(shí),它就查一下這個(gè)表,找出相應(yīng)的 Call ID,然后把它傳給服務(wù)端,服務(wù)端也通過(guò)查表,來(lái)確定客戶端需要調(diào)用的函數(shù),然后執(zhí)行相應(yīng)函數(shù)的代碼。
實(shí)現(xiàn)方式 服務(wù)注冊(cè)中心。
要調(diào)用服務(wù),首先你需要一個(gè)服務(wù)注冊(cè)中心去查詢對(duì)方服務(wù)都有哪些實(shí)例。Dubbo 的服務(wù)注冊(cè)中心是可以配置的,官方推薦使用 Zookeeper。
實(shí)現(xiàn)案例:
RMI(Remote Method Invocation,遠(yuǎn)程方法調(diào)用)也就是 RPC 本身的實(shí)現(xiàn)方式。
圖 9:RMI 架構(gòu)圖
Registry(服務(wù)發(fā)現(xiàn)):
借助 JNDI 發(fā)布并調(diào)用了 RMI服務(wù)。實(shí)際上,JNDI 就是一個(gè)注冊(cè)表,服務(wù)端將服務(wù)對(duì)象放入到注冊(cè)表中,客戶端從注冊(cè)表中獲取服務(wù)對(duì)象。
RMI 服務(wù)在服務(wù)端實(shí)現(xiàn)之后需要注冊(cè)到 RMI Server 上,然后客戶端從指定的 RMI 地址上 Lookup 服務(wù),調(diào)用該服務(wù)對(duì)應(yīng)的方法即可完成遠(yuǎn)程方法調(diào)用。
Registry 是個(gè)很重要的功能,當(dāng)服務(wù)端開發(fā)完服務(wù)之后,要對(duì)外暴露,如果沒有服務(wù)注冊(cè),則客戶端是無(wú)從調(diào)用的,即使服務(wù)端的服務(wù)就在那里。
客戶端怎么把參數(shù)值傳給遠(yuǎn)程的函數(shù)呢?在本地調(diào)用中,我們只需要把參數(shù)壓到棧里,然后讓函數(shù)自己去棧里讀就行。
但是在遠(yuǎn)程過(guò)程調(diào)用時(shí),客戶端跟服務(wù)端是不同的進(jìn)程,不能通過(guò)內(nèi)存來(lái)傳遞參數(shù)。
這時(shí)候就需要客戶端把參數(shù)先轉(zhuǎn)成一個(gè)字節(jié)流,傳給服務(wù)端后,再把字節(jié)流轉(zhuǎn)成自己能讀取的格式。
這個(gè)過(guò)程叫序列化和反序列化。同理,從服務(wù)端返回的值也需要序列化反序列化的過(guò)程。
優(yōu)點(diǎn)
1 簡(jiǎn)單易用開發(fā)成本低
2 跨語(yǔ)言
3 輕量級(jí)數(shù)據(jù)交換
4 非冗長(zhǎng)性(對(duì)比xml標(biāo)簽簡(jiǎn)單括號(hào)閉環(huán))
缺點(diǎn)
1 體積大,影響高并發(fā)
2 無(wú)版本檢查,自己做兼容
3 片段的創(chuàng)建和驗(yàn)證過(guò)程比一般的XML復(fù)雜
4 缺乏命名空間導(dǎo)致信息混合
總結(jié):最簡(jiǎn)單最通用的應(yīng)用協(xié)議,使用廣泛,開發(fā)效率高,性能相對(duì)較低,維護(hù)成本較高。
Protobuf是一種以有效并可擴(kuò)展的格式編碼結(jié)構(gòu)化數(shù)據(jù)的方式。
優(yōu)點(diǎn)
1 跨語(yǔ)言,可自定義數(shù)據(jù)結(jié)構(gòu)。
2 字段被編號(hào),新添加的字段不影響老結(jié)構(gòu)。解決了向后兼容問(wèn)題。
3 自動(dòng)化生成代碼,簡(jiǎn)單易用。
4 二進(jìn)制消息,效率高,性能高。
5 Netty等框架集成了該協(xié)議,提供了編×××提高開發(fā)效率。
缺點(diǎn)
1 二進(jìn)制格式,可讀性差(抓包dump后的數(shù)據(jù)很難看懂)
2 對(duì)象冗余,字段很多,生成的類較大,占用空間。
3 默認(rèn)不具備動(dòng)態(tài)特性(可以通過(guò)動(dòng)態(tài)定義生成消息類型或者動(dòng)態(tài)編譯支持)
總結(jié):簡(jiǎn)單快速上手,高效兼容性強(qiáng),維護(hù)成本較高。
優(yōu)點(diǎn)
1 序列化和RPC支持一站式解決,比pb更方便
2 跨語(yǔ)言,IDL接口定義語(yǔ)言,自動(dòng)生成多語(yǔ)言文件
3 省流量,體積較小
4 包含完整的客戶端/服務(wù)端堆棧,可快速實(shí)現(xiàn)RPC
5 為服務(wù)端提供了多種工作模式,如線程池模型、非阻塞模型
缺點(diǎn)
1 早期版本問(wèn)題較大,0.7以前有兼容性問(wèn)題
2 不支持雙通道
3 rpc方法非線程安全,服務(wù)器容易被掛死,需要串行化。
4 默認(rèn)不具備動(dòng)態(tài)特性(可以通過(guò)動(dòng)態(tài)定義生成消息類型或者動(dòng)態(tài)編譯支持)
5 開發(fā)環(huán)境、編譯較麻煩
總結(jié):跨語(yǔ)言、實(shí)現(xiàn)簡(jiǎn)單,初次使用較麻煩,需要避免使用問(wèn)題和場(chǎng)景限制。
網(wǎng)絡(luò)傳輸:
遠(yuǎn)程調(diào)用往往用在網(wǎng)絡(luò)上,客戶端和服務(wù)端是通過(guò)網(wǎng)絡(luò)連接的。
所有的數(shù)據(jù)都需要通過(guò)網(wǎng)絡(luò)傳輸,因此就需要有一個(gè)網(wǎng)絡(luò)傳輸層。網(wǎng)絡(luò)傳輸層需要把 Call ID 和序列化后的參數(shù)字節(jié)流傳給服務(wù)端,然后再把序列化后的調(diào)用結(jié)果傳回客戶端。
只要能完成這兩者的,都可以作為傳輸層使用。因此,它所使用的協(xié)議其實(shí)是不限的,能完成傳輸就行。
盡管大部分 RPC 框架都使用 TCP 協(xié)議,但其實(shí) UDP 也可以,而 gRPC 干脆就用了 HTTP2。
TCP 的連接是最常見的,簡(jiǎn)要分析基于 TCP 的連接:
通常 TCP 連接可以是按需連接(需要調(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è)連接。
所以,要實(shí)現(xiàn)一個(gè) RPC 框架,只需要把以下三點(diǎn)實(shí)現(xiàn)了就基本完成了:
RPC 核心之網(wǎng)絡(luò)傳輸協(xié)議
在第三節(jié)中說(shuō)明了要實(shí)現(xiàn)一個(gè) RPC,需要選擇網(wǎng)絡(luò)傳輸?shù)姆绞健?/p>
圖 10:網(wǎng)絡(luò)傳輸
在 RPC 中可選的網(wǎng)絡(luò)傳輸方式有多種,可以選擇 TCP 協(xié)議、UDP 協(xié)議、HTTP 協(xié)議。
每一種協(xié)議對(duì)整體的性能和效率都有不同的影響,如何選擇一個(gè)正確的網(wǎng)絡(luò)傳輸協(xié)議呢?首先要搞明白各種傳輸協(xié)議在 RPC 中的工作方式。
由服務(wù)的調(diào)用方與服務(wù)的提供方建立 Socket 連接,并由服務(wù)的調(diào)用方通過(guò) Socket 將需要調(diào)用的接口名稱、方法名稱和參數(shù)序列化后傳遞給服務(wù)的提供方,服務(wù)的提供方反序列化后再利用反射調(diào)用相關(guān)的方法。
最后將結(jié)果返回給服務(wù)的調(diào)用方,整個(gè)基于 TCP 協(xié)議的 RPC 調(diào)用大致如此。
但是在實(shí)例應(yīng)用中則會(huì)進(jìn)行一系列的封裝,如 RMI 便是在 TCP 協(xié)議上傳遞可序列化的 Java 對(duì)象。
該方法更像是訪問(wèn)網(wǎng)頁(yè)一樣,只是它的返回結(jié)果更加單一簡(jiǎn)單。
其大致流程為:
由服務(wù)的調(diào)用者向服務(wù)的提供者發(fā)送請(qǐng)求,這種請(qǐng)求的方式可能是 GET、POST、PUT、DELETE 等中的一種,服務(wù)的提供者可能會(huì)根據(jù)不同的請(qǐng)求方式做出不同的處理,或者某個(gè)方法只允許某種請(qǐng)求方式。
而調(diào)用的具體方法則是根據(jù) URL 進(jìn)行方法調(diào)用,而方法所需要的參數(shù)可能是對(duì)服務(wù)調(diào)用方傳輸過(guò)去的 XML 數(shù)據(jù)或者 JSON 數(shù)據(jù)解析后的結(jié)果,最后返回 JOSN 或者 XML 的數(shù)據(jù)結(jié)果。
由于目前有很多開源的 Web 服務(wù)器,如 Tomcat,所以其實(shí)現(xiàn)起來(lái)更加容易,就像做 Web 項(xiàng)目一樣。
基于 TCP 的協(xié)議實(shí)現(xiàn)的 RPC 調(diào)用,由于 TCP 協(xié)議處于協(xié)議棧的下層,能夠更加靈活地對(duì)協(xié)議字段進(jìn)行定制,減少網(wǎng)絡(luò)開銷,提高性能,實(shí)現(xiàn)更大的吞吐量和并發(fā)數(shù)。
但是需要更多關(guān)注底層復(fù)雜的細(xì)節(jié),實(shí)現(xiàn)的代價(jià)更高。同時(shí)對(duì)不同平臺(tái),如安卓,iOS 等,需要重新開發(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)容),開源的解析工具已經(jīng)相當(dāng)成熟,在其上進(jìn)行二次開發(fā)會(huì)非常便捷和簡(jiǎn)單。
但是由于 HTTP 協(xié)議是上層協(xié)議,發(fā)送包含同等內(nèi)容的信息,使用 HTTP 協(xié)議傳輸所占用的字節(jié)數(shù)會(huì)比使用 TCP 協(xié)議傳輸所占用的字節(jié)數(shù)更高。
因此在同等網(wǎng)絡(luò)下,通過(guò) HTTP 協(xié)議傳輸相同內(nèi)容,效率會(huì)比基于 TCP 協(xié)議的數(shù)據(jù)效率要低,信息傳輸所占用的時(shí)間也會(huì)更長(zhǎng),當(dāng)然壓縮數(shù)據(jù),能夠縮小這一差距。
在 OpenStack 中服務(wù)與服務(wù)之間使用 RESTful API 調(diào)用,而在服務(wù)內(nèi)部則使用 RPC 調(diào)用各個(gè)功能模塊。
正是由于使用了 RPC 來(lái)解耦服務(wù)內(nèi)部功能模塊,使得 OpenStack 的服務(wù)擁有擴(kuò)展性強(qiáng),耦合性低等優(yōu)點(diǎn)。
OpenStack 的 RPC 架構(gòu)中,加入了消息隊(duì)列 RabbitMQ,這樣做的目的是為了保證 RPC 在消息傳遞過(guò)程中的安全性和穩(wěn)定性。
下面分析 OpenStack 中使用 RabbitMQ 如何實(shí)現(xiàn) RPC 的調(diào)用。
RabbitMQ 簡(jiǎn)介
以下摘錄自知乎:
對(duì)于初學(xué)者,舉一個(gè)飯店的例子來(lái)解釋這三個(gè)分別是什么吧。不是百分百恰當(dāng),但是應(yīng)該足以解釋這三者的區(qū)別。
RPC:
假設(shè)你是一個(gè)飯店里的服務(wù)員,顧客向你點(diǎn)菜,但是你不會(huì)做菜,所以你采集了顧客要點(diǎn)什么之后告訴后廚去做顧客點(diǎn)的菜,這叫 RPC(remote procedure call),因?yàn)閺N房的廚師相對(duì)于服務(wù)員而言是另外一個(gè)人(在計(jì)算機(jī)的世界里就是 Remote 的機(jī)器上的一個(gè)進(jìn)程)。廚師做好了的菜就是RPC的返回值。
任務(wù)隊(duì)列和消息隊(duì)列:
本質(zhì)都是隊(duì)列,所以就只舉一個(gè)任務(wù)隊(duì)列的例子。假設(shè)這個(gè)飯店在高峰期顧客很多,而廚師只有很少的幾個(gè),所以服務(wù)員們不得不把單子按下單順序放在廚房的桌子上,供廚師們一個(gè)一個(gè)做,這一堆單子就是任務(wù)隊(duì)列,廚師們每做完一個(gè)菜,就從桌子上的訂單里再取出一個(gè)單子繼續(xù)做菜。
角色分擔(dān)如下圖:
圖 11:RabbitMQ 在 RPC 中角色
使用 RabbitMQ 的好處:
RabbitMQ 的三種類型的交換器
RabbitMQ 使用 Exchange(交換機(jī))和 Queue(隊(duì)列)來(lái)實(shí)現(xiàn)消息隊(duì)列。
在 RabbitMQ 中一共有三種交換機(jī)類型,每一種交換機(jī)類型都有很鮮明的特征。
基于這三種交換機(jī)類型,OpenStack 完成兩種 RPC 的調(diào)用方式。首先簡(jiǎn)單介紹三種交換機(jī)。
圖 12:RabbitMQ 架構(gòu)圖
①?gòu)V播式交換器類型(Fanout)
該類交換器不分析所接收到消息中的 Routing Key,默認(rèn)將消息轉(zhuǎn)發(fā)到所有與該交換器綁定的隊(duì)列中去。
圖 13:廣播式交換機(jī)
②直接式交換器類型(Direct)
該類交換器需要精確匹配 Routing Key 與 Binding Key,如消息的 Routing Key = Cloud,那么該條消息只能被轉(zhuǎn)發(fā)至 Binding Key = Cloud 的消息隊(duì)列中去。
圖 14:直接式交換機(jī)
③主題式交換器(Topic Exchange)
該類交換器通過(guò)消息的 Routing Key 與 Binding Key 的模式匹配,將消息轉(zhuǎn)發(fā)至所有符合綁定規(guī)則的隊(duì)列中。
Binding Key 支持通配符,其中“*”匹配一個(gè)詞組,“#”匹配多個(gè)詞組(包括零個(gè))。
圖 15:主題式交換機(jī)
注:以上四張圖片來(lái)自博客園,如有侵權(quán),請(qǐng)聯(lián)系作者: https://www.cnblogs.com/dwlsxj/p/RabbitMQ.html。
當(dāng)生產(chǎn)者發(fā)送消息 Routing Key=F.C.E 的時(shí)候,這時(shí)候只滿足 Queue1,所以會(huì)被路由到 Queue 中。
如果 Routing Key=A.C.E 這時(shí)候會(huì)被同時(shí)路由到 Queue1 和 Queue2 中,如果 Routing Key=A.F.B 時(shí),這里只會(huì)發(fā)送一條消息到 Queue2 中。
Nova 基于 RabbitMQ 實(shí)現(xiàn)兩種 RPC 調(diào)用:
其中 RPC.CALL 基于請(qǐng)求與響應(yīng)方式,RPC.CAST 只是提供單向請(qǐng)求,兩種 RPC 調(diào)用方式在 Nova 中均有典型的應(yīng)用場(chǎng)景。
RPC.CALL
RPC.CALL 是一種雙向通信流程,即 RabbitMQ 接收消息生產(chǎn)者生成的系統(tǒng)請(qǐng)求消息,消息消費(fèi)者經(jīng)過(guò)處理之后將系統(tǒng)相應(yīng)結(jié)果反饋給調(diào)用程序。
圖 16:RPC.CALL 原理圖
一個(gè)用戶通過(guò) Dashboard 創(chuàng)建一個(gè)虛擬機(jī),界面經(jīng)過(guò)消息封裝后發(fā)送給 NOVA-API。
NOVA-API 作為消息生產(chǎn)者,將該消息以 RPC.CALL 方式通過(guò) Topic 交換器轉(zhuǎn)發(fā)至消息隊(duì)列。
此時(shí),Nova-Compute 作為消息消費(fèi)者,接收該信息并通過(guò)底層虛擬化軟件執(zhí)行相應(yīng)虛擬機(jī)的啟動(dòng)進(jìn)程。
待用戶虛擬機(jī)成功啟動(dòng)之后,Nova-Compute 作為消息生產(chǎn)者通過(guò) Direct 交換器和響應(yīng)的消息隊(duì)列將虛擬機(jī)啟動(dòng)成功響應(yīng)消息反饋給 Nova-API。
此時(shí) Nova-API 作為消息消費(fèi)者接收該消息并通知用戶虛擬機(jī)啟動(dòng)成功。
RPC.CALL 工作原理如下圖:
圖 17:RPC.CALL 具體實(shí)現(xiàn)圖
工作流程:
如果有多個(gè)線程同時(shí)進(jìn)行遠(yuǎn)程方法調(diào)用,這時(shí)建立在 Client Server 之間的 Socket 連接上會(huì)有很多雙方發(fā)送的消息傳遞,前后順序也可能是隨機(jī)的。
Server 處理完結(jié)果后,將結(jié)果消息發(fā)送給 Client,Client 收到很多消息,怎么知道哪個(gè)消息結(jié)果是原先哪個(gè)線程調(diào)用的?
Client 線程每次通過(guò) Socket 調(diào)用一次遠(yuǎn)程接口前,生成一個(gè)唯一的 ID,即 Request ID(Request ID必需保證在一個(gè) Socket 連接里面是唯一的),一般常常使用 AtomicLong 從 0 開始累計(jì)數(shù)字生成唯一 ID。
RPC.CAST
RPC.CAST 的遠(yuǎn)程調(diào)用流程與 RPC.CALL 類似,只是缺少了系統(tǒng)消息響應(yīng)流程。
一個(gè) Topic 消息生產(chǎn)者發(fā)送系統(tǒng)請(qǐng)求消息到 Topic 交換器,Topic 交換器根據(jù)消息的 Routing Key 將消息轉(zhuǎn)發(fā)至共享消息隊(duì)列。
與共享消息隊(duì)列相連的所有 Topic 消費(fèi)者接收該系統(tǒng)請(qǐng)求消息,并把它傳遞給響應(yīng)的服務(wù)端進(jìn)行處理。
其調(diào)用流程如圖所示:
圖 18:RPC.CAST 原理圖
連接設(shè)計(jì)
RabbitMQ 實(shí)現(xiàn)的 RPC 對(duì)網(wǎng)絡(luò)的一般設(shè)計(jì)思路:消費(fèi)者是長(zhǎng)連接,發(fā)送者是短連接。但可以自由控制長(zhǎng)連接和短連接。
一般消費(fèi)者是長(zhǎng)連接,隨時(shí)準(zhǔn)備接收處理消息;而且涉及到 RabbitMQ Queues、Exchange 的 auto-deleted 等沒特殊需求沒必要做短連接。發(fā)送者可以使用短連接,不會(huì)長(zhǎng)期占住端口號(hào),節(jié)省端口資源。
Nova 中 RPC 代碼設(shè)計(jì):
簡(jiǎn)單對(duì)比 RPC 和 Restful API
REST 最大的幾個(gè)特點(diǎn)為:資源、統(tǒng)一接口、URI 和無(wú)狀態(tài)。
①資源
所謂”資源”,就是網(wǎng)絡(luò)上的一個(gè)實(shí)體,或者說(shuō)是網(wǎng)絡(luò)上的一個(gè)具體信息。它可以是一段文本、一張圖片、一首歌曲、一種服務(wù),就是一個(gè)具體的實(shí)在。
②統(tǒng)一接口
RESTful 架構(gòu)風(fēng)格規(guī)定,數(shù)據(jù)的元操作,即 CRUD(Create,Read,Update 和 Delete,即數(shù)據(jù)的增刪查改)操作,分別對(duì)應(yīng)于 HTTP 方法:GET 用來(lái)獲取資源,POST 用來(lái)新建資源(也可以用于更新資源),PUT 用來(lái)更新資源,DELETE 用來(lái)刪除資源,這樣就統(tǒng)一了數(shù)據(jù)操作的接口,僅通過(guò) HTTP 方法,就可以完成對(duì)數(shù)據(jù)的所有增刪查改工作。
③URL
可以用一個(gè) URI(統(tǒng)一資源定位符)指向資源,即每個(gè) URI 都對(duì)應(yīng)一個(gè)特定的資源。
要獲取這個(gè)資源,訪問(wèn)它的 URI 就可以,因此 URI 就成了每一個(gè)資源的地址或識(shí)別符。
④無(wú)狀態(tài)
所謂無(wú)狀態(tài)的,即所有的資源,都可以通過(guò) URI 定位,而且這個(gè)定位與其他資源無(wú)關(guān),也不會(huì)因?yàn)槠渌Y源的變化而改變。有狀態(tài)和無(wú)狀態(tài)的區(qū)別,舉個(gè)簡(jiǎn)單的例子說(shuō)明一下。
如查詢員工的工資,如果查詢工資是需要登錄系統(tǒng),進(jìn)入查詢工資的頁(yè)面,執(zhí)行相關(guān)操作后,獲取工資的多少,則這種情況是有狀態(tài)的。
因?yàn)椴樵児べY的每一步操作都依賴于前一步操作,只要前置操作不成功,后續(xù)操作就無(wú)法執(zhí)行。
如果輸入一個(gè) URI即可得到指定員工的工資,則這種情況是無(wú)狀態(tài)的,因?yàn)楂@取工資不依賴于其他資源或狀態(tài)。
且這種情況下,員工工資是一個(gè)資源,由一個(gè) URI與之對(duì)應(yīng),可以通過(guò) HTTP 中的 GET 方法得到資源,這是典型的 RESTful 風(fēng)格。
面對(duì)對(duì)象不同:
RESTful 是面向資源的設(shè)計(jì)架構(gòu),但在系統(tǒng)中有很多對(duì)象不能抽象成資源,比如登錄,修改密碼等而 RPC 可以通過(guò)動(dòng)作去操作資源。所以在操作的全面性上 RPC 大于 RESTful。
傳輸效率:
復(fù)雜度:
RPC 實(shí)現(xiàn)(參見第一節(jié))需要實(shí)現(xiàn)編碼,序列化,網(wǎng)絡(luò)傳輸?shù)取6?RESTful 不要關(guān)注這些,RESTful 實(shí)現(xiàn)更簡(jiǎn)單。
靈活性:
RPC 主要用于公司內(nèi)部的服務(wù)調(diào)用,性能消耗低,傳輸效率高,實(shí)現(xiàn)復(fù)雜。
HTTP 主要用于對(duì)外的異構(gòu)環(huán)境,瀏覽器接口調(diào)用,App 接口調(diào)用,第三方接口調(diào)用等。
RPC 使用場(chǎng)景(大型的網(wǎng)站,內(nèi)部子系統(tǒng)較多、接口非常多的情況下適合使用 RPC):
https://developer.51cto.com/art/201906/597963.htm
http://www.mamicode.com/info-detail-2443824.html
Java技術(shù)倉(cāng)庫(kù)《Java程序員復(fù)習(xí)指南》
https://github.com/h3pl/Java-Tutorial
整合全網(wǎng)優(yōu)質(zhì)Java學(xué)習(xí)內(nèi)容,幫助你從基礎(chǔ)到進(jìn)階系統(tǒng)化復(fù)習(xí)Java