RPC采用客戶機(jī)/服務(wù)器模式。請(qǐng)求程序就是一個(gè)客戶機(jī),而服務(wù)提供程序就是一個(gè)服務(wù)器。首先,客戶機(jī)調(diào)用進(jìn)程發(fā)送一個(gè)有進(jìn)程參數(shù)的調(diào)用信息到服務(wù)進(jìn)程,然后等待應(yīng)答信息。在服務(wù)器端,進(jìn)程保持睡眠狀態(tài)直到調(diào)用信息的到達(dá)為止。當(dāng)一個(gè)調(diào)用信息到達(dá),服務(wù)器獲得進(jìn)程參數(shù),計(jì)算結(jié)果,發(fā)送答復(fù)信息,然后等待下一個(gè)調(diào)用信息,最后,客戶端調(diào)用進(jìn)程接收答復(fù)信息,獲得進(jìn)程結(jié)果,然后調(diào)用執(zhí)行繼續(xù)進(jìn)行。
網(wǎng)站建設(shè)公司,為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì)及定制網(wǎng)站建設(shè)服務(wù),專注于成都定制網(wǎng)頁(yè)設(shè)計(jì),高端網(wǎng)頁(yè)制作,對(duì)戶外休閑椅等多個(gè)行業(yè)擁有豐富的網(wǎng)站建設(shè)經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。專業(yè)網(wǎng)站設(shè)計(jì),網(wǎng)站優(yōu)化推廣哪家好,專業(yè)seo優(yōu)化排名優(yōu)化,H5建站,響應(yīng)式網(wǎng)站。
在一個(gè)典型 RPC 的使用場(chǎng)景中,包含了服務(wù)發(fā)現(xiàn)、負(fù)載、容錯(cuò)、網(wǎng)絡(luò)傳輸、序列化等組件,其中“RPC 協(xié)議”就指明了程序如何進(jìn)行網(wǎng)絡(luò)傳輸和序列化
運(yùn)行時(shí),一次客戶機(jī)對(duì)服務(wù)器的RPC調(diào)用,其內(nèi)部操作大致有如下十步:
1.調(diào)用客戶端句柄;執(zhí)行傳送參數(shù)
2.調(diào)用本地系統(tǒng)內(nèi)核發(fā)送網(wǎng)絡(luò)消息
3.消息傳送到遠(yuǎn)程主機(jī)
4.服務(wù)器句柄得到消息并取得參數(shù)
5.執(zhí)行遠(yuǎn)程過程
6.執(zhí)行的過程將結(jié)果返回服務(wù)器句柄
7.服務(wù)器句柄返回結(jié)果,調(diào)用遠(yuǎn)程系統(tǒng)內(nèi)核
8.消息傳回本地主機(jī)
9.客戶句柄由內(nèi)核接收消息
10.客戶接收句柄返回的數(shù)據(jù)
RPC 的核心功能是指實(shí)現(xiàn)一個(gè) RPC 最重要的功能模塊,就是上圖中的”RPC 協(xié)議”部分:
下面分別介紹核心 RPC 框架的重要組成:
一次 RPC 調(diào)用流程如下:
接口調(diào)用通常包含兩個(gè)部分,序列化和通信協(xié)議。常見的序列化協(xié)議包括json、xml、hession、protobuf、thrift、text、bytes等;通信比較流行的是http、soap、websockect,RPC通?;赥CP實(shí)現(xiàn)。那么restful使用的序列化協(xié)議通常是json,通信協(xié)議是http;rpc是一種通信協(xié)議,因此如果序列化使用json的話,那么就是json-rpc
RPC 的核心功能主要由 5 個(gè)模塊組成,如果想要自己實(shí)現(xiàn)一個(gè) RPC,最簡(jiǎn)單的方式要實(shí)現(xiàn)三個(gè)技術(shù)點(diǎn),分別是:
服務(wù)尋址可以使用 Call ID 映射。在本地調(diào)用中,函數(shù)體是直接通過函數(shù)指針來指定的,但是在遠(yuǎn)程調(diào)用中,函數(shù)指針是不行的,因?yàn)閮蓚€(gè)進(jìn)程的地址空間是完全不一樣的。
所以在 RPC 中,所有的函數(shù)都必須有自己的一個(gè) ID。這個(gè) ID 在所有進(jìn)程中都是唯一確定的。
客戶端在做遠(yuǎn)程過程調(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ù)端也通過查表,來確定客戶端需要調(diào)用的函數(shù),然后執(zhí)行相應(yīng)函數(shù)的代碼。
實(shí)現(xiàn)方式:服務(wù)注冊(cè)中心。
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è),則客戶端是無從調(diào)用的,即使服務(wù)端的服務(wù)就在那里
客戶端怎么把參數(shù)值傳給遠(yuǎn)程的函數(shù)呢?在本地調(diào)用中,我們只需要把參數(shù)壓到棧里,然后讓函數(shù)自己去棧里讀就行。
但是在遠(yuǎn)程過程調(diào)用時(shí),客戶端跟服務(wù)端是不同的進(jìn)程,不能通過內(nèi)存來傳遞參數(shù)。
這時(shí)候就需要客戶端把參數(shù)先轉(zhuǎn)成一個(gè)字節(jié)流,傳給服務(wù)端后,再把字節(jié)流轉(zhuǎn)成自己能讀取的格式。
只有二進(jìn)制數(shù)據(jù)才能在網(wǎng)絡(luò)中傳輸,序列化和反序列化的定義是:
這個(gè)過程叫序列化和反序列化。同理,從服務(wù)端返回的值也需要序列化反序列化的過程。
網(wǎng)絡(luò)傳輸:遠(yuǎn)程調(diào)用往往用在網(wǎng)絡(luò)上,客戶端和服務(wù)端是通過網(wǎng)絡(luò)連接的。
所有的數(shù)據(jù)都需要通過網(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í)有無數(shù)據(jù)包的發(fā)送,可以配合心跳檢測(cè)機(jī)制定期檢測(cè)建立的連接是否存活有效),多個(gè)遠(yuǎn)程過程調(diào)用共享同一個(gè)連接。
所以,要實(shí)現(xiàn)一個(gè) RPC 框架,只需要把以下三點(diǎn)實(shí)現(xiàn)了就基本完成了:
在 RPC 中可選的網(wǎng)絡(luò)傳輸方式有多種,可以選擇 TCP 協(xié)議、UDP 協(xié)議、HTTP 協(xié)議。
由服務(wù)的調(diào)用方與服務(wù)的提供方建立 Socket 連接,并由服務(wù)的調(diào)用方通過 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ǎ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)用方傳輸過去的 XML 數(shù)據(jù)或者 JSON 數(shù)據(jù)解析后的結(jié)果,返回 JOSN 或者 XML 的數(shù)據(jù)結(jié)果。
由于目前有很多開源的 Web 服務(wù)器,如 Tomcat,所以其實(shí)現(xiàn)起來更加容易,就像做 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ā)出不同的工具包來進(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é)議也需要序列化和反序列化,不過這不是該協(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ò)下,通過 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 來解耦服務(wù)內(nèi)部功能模塊,使得 OpenStack 的服務(wù)擁有擴(kuò)展性強(qiáng),耦合性低等優(yōu)點(diǎn)。
OpenStack 的 RPC 架構(gòu)中,加入了消息隊(duì)列 RabbitMQ,這樣做的目的是為了保證 RPC 在消息傳遞過程中的安全性和穩(wěn)定性。
下面分析 OpenStack 中使用 RabbitMQ 如何實(shí)現(xiàn) RPC 的調(diào)用。
使用 RabbitMQ 的好處:
RPC 主要用于公司內(nèi)部的服務(wù)調(diào)用,性能消耗低,傳輸效率高,實(shí)現(xiàn)復(fù)雜
RESTful API 主要用于對(duì)外的異構(gòu)環(huán)境,瀏覽器接口調(diào)用,App 接口調(diào)用,第三方接口調(diào)用等
RPC 使用場(chǎng)景(大型的網(wǎng)站,內(nèi)部子系統(tǒng)較多、接口非常多的情況下適合使用 RPC):