遠(yuǎn)程過(guò)程調(diào)用(Remote Procedure Call, RPC)是從一臺(tái)機(jī)器上通過(guò)參數(shù)傳遞的方式調(diào)用另一臺(tái)機(jī)器上的一個(gè)函數(shù)或方法并得到返回的結(jié)果告丢。這樣的方法又可以稱(chēng)為服務(wù)羊赵。RPC隱藏了底層的通訊細(xì)節(jié),不需要直接處理Socket通訊或Http通訊相恃,并將這些細(xì)節(jié)封裝成一個(gè)服務(wù)(Service)甚脉。RPC是一個(gè)請(qǐng)求響應(yīng)模型台谊〈植郑客戶(hù)端發(fā)起請(qǐng)求,服務(wù)器返回響應(yīng)奸绷。
在進(jìn)行詳細(xì)的闡述之前梗夸,RPC的請(qǐng)求響應(yīng)模型可以簡(jiǎn)單的理解為類(lèi)似于Http的工作方式。
在使用形式上号醉,RPC像調(diào)用本地函數(shù)或方法一樣反症,去調(diào)用遠(yuǎn)程的函數(shù)或方法。
為什么需要RPC
在設(shè)計(jì)一個(gè)非分布式應(yīng)用時(shí)畔派,程序各個(gè)模塊之間的交互都通過(guò)方法調(diào)用進(jìn)行數(shù)據(jù)傳遞铅碍。例如,dao模塊通過(guò)定義接口的方式暴露一些方法线椰,供給上層調(diào)用胞谈,業(yè)務(wù)邏輯層調(diào)用這些方法,傳入一些參數(shù)憨愉,就可以對(duì)持久層的數(shù)據(jù)進(jìn)行讀寫(xiě)訪(fǎng)問(wèn)烦绳。這種單臺(tái)主機(jī)就能完成的數(shù)據(jù)交互就叫做集中式運(yùn)算(centralized computing)。當(dāng)數(shù)據(jù)交互的需求轉(zhuǎn)移到分布式運(yùn)算(distributed computing)系統(tǒng)中時(shí)配紫,由于本模塊所需要的數(shù)據(jù)可能不在本地的內(nèi)存或者持久層中爵嗅,所以要通過(guò)網(wǎng)絡(luò)調(diào)用的方式進(jìn)行數(shù)據(jù)傳輸,網(wǎng)絡(luò)傳輸?shù)脑冀鉀Q方案是使用socket笨蚁。
Socket是Client/Server模型網(wǎng)絡(luò)的基本組成部分睹晒。它們?yōu)槌绦蛱峁┝艘粋€(gè)相對(duì)簡(jiǎn)單的機(jī)制,可以在遠(yuǎn)程或本地機(jī)器上建立與另一個(gè)程序的連接并來(lái)回發(fā)送消息括细。甚至可以使用Socket進(jìn)行系統(tǒng)調(diào)用伪很。但是原始的Socket必須使用輸入/輸出接口(input/output)來(lái)對(duì)分布式系統(tǒng)進(jìn)行數(shù)據(jù)交互,這和傳統(tǒng)的通過(guò)接口暴露方法服務(wù)的方式有很大差距奋单,也不利于服務(wù)提供模塊對(duì)底層服務(wù)的管理锉试。為了解決這個(gè)局限性,1984年览濒,Birrell和Nelson設(shè)計(jì)了一個(gè)機(jī)制呆盖,允許程序在其他機(jī)器上調(diào)用程序。主機(jī)A上的進(jìn)程可以對(duì)主機(jī)B的過(guò)程進(jìn)行調(diào)用贷笛,此時(shí)A上的進(jìn)程被暫停并且繼續(xù)執(zhí)行B应又,當(dāng)B返回時(shí)傳遞返回值給A并繼續(xù)執(zhí)行A中的進(jìn)程。這種機(jī)制被稱(chēng)為遠(yuǎn)程過(guò)程調(diào)用(RPC)乏苦。RPC的主要目標(biāo)是讓構(gòu)建分布式計(jì)算(應(yīng)用)更容易株扛,在提供強(qiáng)大的遠(yuǎn)程調(diào)用能力時(shí)不損失本地調(diào)用的語(yǔ)義簡(jiǎn)潔性尤筐。
本地方法調(diào)用的實(shí)現(xiàn)
由于編譯器和系統(tǒng)結(jié)構(gòu)的不同,本地方法的調(diào)用的過(guò)程可能會(huì)有不同洞就。JVM使用基于棧的指令系統(tǒng)盆繁,這里主要分析基于棧的指令系統(tǒng)來(lái)分析。
處理器會(huì)提供某種類(lèi)型的call
指令旬蟋,這條指令會(huì)將堆棧中下一條指令的地址壓入操作數(shù)棧油昂,并將處理器的訪(fǎng)問(wèn)控制轉(zhuǎn)移到由調(diào)用指定的地址。當(dāng)調(diào)用結(jié)束后倾贰,通過(guò)一個(gè)return
指令秕狰,目標(biāo)地址從棧頂彈出,處理器釋放對(duì)該地址的控制權(quán)躁染。在這個(gè)過(guò)程中,編譯器會(huì)執(zhí)行類(lèi)似識(shí)別參數(shù)架忌、壓參數(shù)入棧吞彤、執(zhí)行調(diào)用指令等細(xì)節(jié)。在被調(diào)用的函數(shù)中叹放,編譯器存儲(chǔ)可能被標(biāo)記為clobbered的寄存器的值饰恕,為本地變量分配棧幀,然后在返回之前恢復(fù)寄存器和釋放椌觯空間埋嵌。
指令系統(tǒng)共有四種分類(lèi):堆棧型,累加器型俱恶,寄存器-存儲(chǔ)器型和寄存器-寄存器型雹嗦。分類(lèi)的依據(jù)是操作數(shù)的來(lái)源。
RPC通用架構(gòu)及典型流程
本地方法調(diào)用沒(méi)有一個(gè)步驟是涉及到網(wǎng)絡(luò)的合是,為了令編譯器模擬在不同系統(tǒng)之間的方法調(diào)用過(guò)程了罪,需要一個(gè)比Socket更高級(jí)別的定義。它需要一個(gè)操作系統(tǒng)級(jí)別(operating system level)的協(xié)議構(gòu)造聪全,使遠(yuǎn)程過(guò)程不必通過(guò)Socket調(diào)用泊藕,而是通過(guò)一個(gè)語(yǔ)言級(jí)別(language-level)的架構(gòu)。
遠(yuǎn)程過(guò)程調(diào)用協(xié)議的架構(gòu)看起來(lái)是這個(gè)樣子:
![RPC](http://image.gblau.com/rpc-flow.png)
圖片來(lái)源:UNIX網(wǎng)絡(luò)編程(UNIX Network Programming)英文版第693頁(yè)难礼,作者W. Richard Steven娃圆。
進(jìn)行RPC的核心便是Stub中的函數(shù)。在客戶(hù)端上蛾茉,Stub中的函數(shù)看起來(lái)真的是本地調(diào)用的函數(shù)讼呢,例如dao定義的暴露給業(yè)務(wù)邏輯層調(diào)用的接口,但實(shí)際上包含通過(guò)網(wǎng)絡(luò)發(fā)送和接收消息的代碼谦炬。
什么是Stub吝岭?Stub是一段部署在分布式系統(tǒng)Client端的代碼,一方面接收應(yīng)用層的參數(shù),并對(duì)其包裝(pakage)后通過(guò)socket發(fā)送到Server端窜管,另一方面接收Server端序列化后的結(jié)果數(shù)據(jù)散劫,解除包裝后交給Client端應(yīng)用層。
Skeleton功能與Client Stub相反幕帆,部署在Server端获搏,從傳輸層接收序列化參數(shù),將包裝的參數(shù)再轉(zhuǎn)換后交給Server端的應(yīng)用層失乾,并將應(yīng)用層的執(zhí)行結(jié)果包裝后最終傳送給Client端Stub常熙。
所以客戶(hù)端調(diào)用一個(gè)client stub
的方法并獲取返回結(jié)果,就完成了遠(yuǎn)程過(guò)程調(diào)用碱茁。在這之間的步驟大概如下裸卫。
- 客戶(hù)端調(diào)用
client stub
中的過(guò)程(procedure),因?yàn)?code>client stub部署在客戶(hù)端纽竣,所以調(diào)用起來(lái)和調(diào)用本地方法看上去是一樣的墓贿。 -
client stub
對(duì)客戶(hù)端傳入的參數(shù)進(jìn)行包裝(package),例如進(jìn)行特定RPC框架的標(biāo)準(zhǔn)格式轉(zhuǎn)換蜓氨,并包裝后的數(shù)據(jù)構(gòu)建成一個(gè)或者多個(gè)網(wǎng)絡(luò)消息聋袋。這個(gè)過(guò)程成為編組(marshaling),需要將數(shù)據(jù)序列化為平面化的字節(jié)數(shù)組穴吹。 - 通過(guò)使用Socket接口對(duì)本地內(nèi)核進(jìn)行系統(tǒng)調(diào)用幽勒,
client stub
將網(wǎng)絡(luò)消息發(fā)送到遠(yuǎn)程系統(tǒng)。 - 網(wǎng)絡(luò)消息由內(nèi)核通過(guò)某種協(xié)議(例如無(wú)連接的UDP港令,面向連接的TCP)傳輸?shù)竭h(yuǎn)程系統(tǒng)啥容。
-
skeleton
對(duì)來(lái)自消息的參數(shù)進(jìn)行解包裝,將它們從標(biāo)準(zhǔn)網(wǎng)絡(luò)格式轉(zhuǎn)換成特定于機(jī)器的形式顷霹。 -
skeleton
使用這些參數(shù)調(diào)用server端的函數(shù)或者方法(對(duì)客戶(hù)端來(lái)說(shuō)即遠(yuǎn)程過(guò)程)干毅。 -
skeleton
獲取返回結(jié)果,并重新包裝泼返、編組為消息發(fā)送回客戶(hù)端硝逢。 -
client stub
從本地內(nèi)核讀取網(wǎng)絡(luò)中的結(jié)果并進(jìn)行轉(zhuǎn)換,返回給客戶(hù)端绅喉∏耄客戶(hù)端代碼繼續(xù)執(zhí)行,調(diào)用結(jié)束柴罐。
RPC相對(duì)于Socket的優(yōu)勢(shì)
RPC相對(duì)于原始的Socket接口徽缚,將所有的網(wǎng)絡(luò)代碼隱藏到Stub的函數(shù)或方法中,應(yīng)用程序不必?fù)?dān)心Socket革屠、端口號(hào)凿试、數(shù)據(jù)轉(zhuǎn)換和解析等底層細(xì)節(jié)排宰。帶來(lái)的優(yōu)勢(shì)主要體現(xiàn)在以下兩點(diǎn):
- 使用過(guò)程調(diào)用語(yǔ)義來(lái)調(diào)用遠(yuǎn)程函數(shù)并獲得響應(yīng)
- 降低編寫(xiě)分布式應(yīng)用程序的開(kāi)發(fā)成本
RPC協(xié)議在協(xié)議分層體系中的位置
計(jì)算機(jī)網(wǎng)絡(luò)中主流的協(xié)議分層體系即OSI和TCP/IP。在OSI參考模型上那婉,RPC跨越會(huì)話(huà)層和展示層(session and presentation layers, 層5和層6)板甘。TCP/IP協(xié)議族中,RPC屬于應(yīng)用層的內(nèi)容详炬。
RPC的優(yōu)勢(shì)
- 不用考慮端口號(hào)的選擇問(wèn)題盐类,RPC封裝了對(duì)可用端口號(hào)的選擇并綁定。
- 獨(dú)立于運(yùn)輸層呛谜,由于skeleton是代碼自動(dòng)生成的在跳,所以會(huì)自動(dòng)兼容傳輸層的協(xié)議∫海客戶(hù)端也可以動(dòng)態(tài)選擇協(xié)議猫妙,因?yàn)榘l(fā)送和接收消息的代碼是自動(dòng)生成的,業(yè)務(wù)層無(wú)需關(guān)心這些問(wèn)題聚凹。
- 客戶(hù)端上的應(yīng)用程序只需要知道一個(gè)傳輸?shù)刂罚贺?fù)責(zé)告訴應(yīng)用程序在哪里連接一組給定的服務(wù)器功能的名稱(chēng)服務(wù)器割坠。
- 使用函數(shù)調(diào)用模型代替Socket接口
RPC實(shí)現(xiàn)要點(diǎn)
實(shí)現(xiàn)一個(gè)RPC,一般有如下幾點(diǎn)需要考慮元践。
參數(shù)傳遞
一般來(lái)說(shuō)參數(shù)傳遞可以有引用傳遞和值傳遞。由于遠(yuǎn)端和本地端內(nèi)存位置可能有差異童谒,所以引用傳遞是沒(méi)有意義的单旁。如果是引用型數(shù)據(jù)結(jié)構(gòu),必須轉(zhuǎn)換成平面結(jié)構(gòu)饥伊。例如樹(shù)必須轉(zhuǎn)換成扁平化樹(shù)(flattened tree)象浑。
數(shù)據(jù)表示
在本地系統(tǒng)上不存在數(shù)據(jù)不兼容問(wèn)題,因?yàn)閿?shù)據(jù)格式總是一樣的琅豆。而網(wǎng)絡(luò)調(diào)用中愉豺,遠(yuǎn)程機(jī)器可能具有不同的字節(jié)順序,不同的整數(shù)大小以及不同的浮點(diǎn)表示茫因。所以在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)需要進(jìn)行序列化蚪拦。
IP協(xié)議強(qiáng)制對(duì)header中的所有16位和32位字段使用大端字節(jié)排序。而RPC中需要一個(gè)標(biāo)準(zhǔn)的數(shù)據(jù)結(jié)構(gòu)冻押。一般有隱式(implicit typing)和顯式(explicit typing)兩種
- 隱式:只傳輸值驰贷,而不是變量的名稱(chēng)或類(lèi)型。
- 顯式:每個(gè)字段的類(lèi)型與值一起傳輸洛巢。
JSON括袒、Protocol Buffers、XML都是顯式格式稿茉。
傳輸協(xié)議
某些RPC實(shí)現(xiàn)只允許使用一個(gè)傳輸層協(xié)議(例如TCP)锹锰。大多數(shù)RPC支持實(shí)現(xiàn)多個(gè)并允許用戶(hù)選擇芥炭。
主機(jī)和端口綁定
我們需要找到一臺(tái)遠(yuǎn)程主機(jī),并在主機(jī)上找到合適的進(jìn)程(端口或傳輸?shù)刂罚┦鸦邸R粋€(gè)解決方案是維護(hù)一個(gè)中央數(shù)據(jù)庫(kù)园蝠,可以找到一個(gè)提供服務(wù)類(lèi)型的主機(jī)。
此外還需要考慮錯(cuò)誤重試糕伐、性能砰琢、安全性問(wèn)題。
Stub代碼生成
很多主流的開(kāi)發(fā)語(yǔ)言并沒(méi)有生成Stub代碼的語(yǔ)法良瞧,所以不能直接支持RPC陪汽。一個(gè)比較通用的解決辦法是提供一個(gè)編譯器把Client/Server Stub代碼編譯出來(lái):
![Stub](http://image.gblau.com/rpc-compilation.png)
由于RPC的跨平臺(tái)特性,所以需要一個(gè)平臺(tái)無(wú)關(guān)的語(yǔ)言來(lái)描述這種RPC接口的特性褥蚯,這樣的語(yǔ)言就叫做接口描述語(yǔ)言(interface definition language, IDL)挚冤。加入IDL后,整個(gè)流程大概就是這個(gè)樣子:
![圖片來(lái)自美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì):序列化和反序列化](http://image.gblau.com/gbau-SerializationComponents.jpg)
接口描述語(yǔ)言
接口描述語(yǔ)言用于描述接口定義赞庶,接口定義就像是Java接口的方法聲明训挡,RPC編譯后,這些聲明就會(huì)織入端中歧强。WebService的WSDL(XML為基礎(chǔ))是一個(gè)IDL的例子澜薄。
很多數(shù)據(jù)表示格式本身也作為RPC中序列化的數(shù)據(jù)結(jié)構(gòu),也能作為IDL編譯Stub代碼摊册。比如Yaml肤京、Json、xml茅特、PB等等忘分,這些都可以作為接口描述語(yǔ)言。
關(guān)于IDL的選擇參考Api 體系架構(gòu)分享(上)
早期的RPC
第一代RPC不支持對(duì)象的傳遞白修,比較典型的有ONC RPC妒峦,OSF RPC。
面向?qū)ο蟮腞PC
隨著面向?qū)ο笳Z(yǔ)言的流行兵睛,現(xiàn)有的RPC機(jī)制和框架實(shí)現(xiàn)雖然能夠完成需求肯骇,但是不支持面向?qū)ο蟮牟僮鳌@鐝倪h(yuǎn)程類(lèi)中實(shí)例化一個(gè)對(duì)象祖很、跟蹤對(duì)象實(shí)例累盗、多態(tài)支持等。加入這些面向?qū)ο蟮闹С殖蔀橐环N趨勢(shì)突琳。
微軟的COM和DCOM
COM若债,包括后來(lái)的DCOM、COM+拆融,都并沒(méi)有真正實(shí)現(xiàn)跨平臺(tái)蠢琳,它們主要用于Windows啊终,是微軟實(shí)現(xiàn)的RPC框架。COM的序列化的原理利用了編譯器中虛表傲须,使得其學(xué)習(xí)成本巨大蓝牲。由于序列化的數(shù)據(jù)與編譯器緊耦合,擴(kuò)展屬性非常麻煩泰讽。
想一下這個(gè)場(chǎng)景例衍,工程師需要是簡(jiǎn)單的序列化協(xié)議,但卻要先掌握語(yǔ)言編譯器已卸,可想而知佛玄。
和大多數(shù)早期RPC系統(tǒng)一樣,DCOM也不能很好地跨越防火墻累澡,因此防火墻必須允許流量在ORPC和DCOM使用的某些端口之間流動(dòng)梦抢。
CORBA
CORBA是早期比較好的實(shí)現(xiàn)了跨平臺(tái),跨語(yǔ)言的序列化協(xié)議(RPC框架)愧哟。CORBAR為了解決異構(gòu)平臺(tái)的 RPC奥吩,首先使用IDL來(lái)定義遠(yuǎn)程接口,并將其映射到特定的平臺(tái)語(yǔ)言中蕊梧。但是CORBA太復(fù)雜霞赫,其參與方過(guò)多帶來(lái)的版本過(guò)多,版本之間兼容性又差肥矢,最終導(dǎo)致COBRA的消亡端衰。
J2SE 1.3之后的版本提供了基于CORBA協(xié)議的RMI-IIOP技術(shù),這使得Java開(kāi)發(fā)者可以采用純粹的Java語(yǔ)言進(jìn)行CORBA的開(kāi)發(fā)橄抹。
CORBA的IDL看起來(lái)像這個(gè)樣子:
Module StudentObject {
Struct StudentInfo {
String name;
int id;
float gpa;
};
exception Unknown {};
interface Student {
StudentInfo getinfo(in string name)
raises(unknown);
void putinfo(in StudentInfo data);
};
};
Java RMI
Java RMI沒(méi)有IDL靴迫,所以也就不支持跨平臺(tái)惕味,但是對(duì)于Java程序員而言顯得更直接簡(jiǎn)單楼誓,降低使用的學(xué)習(xí)成本。
除了跨平臺(tái)名挥,Java RMI還有一個(gè)問(wèn)題是其序列化機(jī)制疟羹。使用Java序列化寫(xiě)出元數(shù)據(jù)(meta-data)是非常昂貴的。Java Serializable序列化不僅寫(xiě)入完整類(lèi)名禀倔,也包含整個(gè)類(lèi)的定義榄融,包含所有被引用的類(lèi)。類(lèi)定義可以是相當(dāng)大的救湖,可能會(huì)構(gòu)成性能和效率的問(wèn)題愧杯,當(dāng)然這是編寫(xiě)一個(gè)單一的對(duì)象。如果序列化大量相同的類(lèi)的對(duì)象鞋既,這時(shí)類(lèi)定義的開(kāi)銷(xiāo)通常不是一個(gè)大問(wèn)題力九。除此之外耍铜,如果對(duì)象有一個(gè)類(lèi)的引用,那么Java序列化將寫(xiě)入整個(gè)類(lèi)的定義跌前,不只是類(lèi)的名稱(chēng)棕兼,
支持Web的RPC
傳統(tǒng)的RPC協(xié)議也可以在Web下工作,但是它的Socket端口是動(dòng)態(tài)選擇的抵乓。但是防火墻可能為了安全性限制大部分端口的訪(fǎng)問(wèn)伴挚,只允許開(kāi)啟某些協(xié)議端口,并檢查協(xié)議格式是否正確灾炭,例如是否是一個(gè)正確的HTTP請(qǐng)求茎芋。
XML-RPC
XML-RPC是1998年設(shè)計(jì)的一種RPC消息傳遞協(xié)議,用于將程序請(qǐng)求和響應(yīng)編入人可讀的XML中咆贬。XML-RPC中败徊,參數(shù)使用XML格式作為數(shù)據(jù)結(jié)構(gòu),并通過(guò)HTTP協(xié)議傳輸掏缎,不必為RPC服務(wù)器應(yīng)用程序打開(kāi)其他端口皱蹦,解決了傳統(tǒng)的企業(yè)防火墻的端口限制問(wèn)題。
XML每個(gè)字段的類(lèi)型與值一起傳輸眷蜈,是顯式傳輸?shù)臄?shù)據(jù)結(jié)構(gòu)沪哺。
SOAP和Web Service
SOAP(Simple Object Access Protocol)是隨著XML-RPC的流行而發(fā)展起來(lái)的一種規(guī)范化的對(duì)象傳輸協(xié)議。
由于該協(xié)議一點(diǎn)兒也不簡(jiǎn)單酌儒,并且不限于訪(fǎng)問(wèn)對(duì)象辜妓,因此該首字母縮略詞已被丟棄。
SOAP使用XML格式作為無(wú)狀態(tài)消息交換格式忌怎,支持包括RPC式的過(guò)程調(diào)用以及multipart響應(yīng)籍滴。但是SOAP只是提供一個(gè)標(biāo)準(zhǔn)的消息傳遞結(jié)構(gòu),為了正確創(chuàng)建SOAP消息榴啸,還要一種描述服務(wù)的方法孽惰。Web Service使用WSDL(Web Services Description Language)來(lái)描述Web Service的服務(wù)。這是一個(gè)XML文檔鸥印,可以被送入一個(gè)程序勋功,該程序?qū)⑸蓪l(fā)送和接收SOAP消息的軟件。WSDL就是一個(gè)IDL库说,用于生成Stub狂鞋。
SOAP和XML-RPC的區(qū)別:
- SOAP設(shè)計(jì)更復(fù)雜,功能更強(qiáng)大
- XML-RP不需要對(duì)參數(shù)命名潜的,按傳入順序傳入和讀出骚揍;SOAP通過(guò)參數(shù)名確定參數(shù),無(wú)順序啰挪。
- XML-RPC更適配Python
SOAP和XML-RPC的區(qū)別可以查看Difference Between RPC and SOAP
REST
REST(Representational State Transfer)遵循Web原則信不,使用HTTP作為協(xié)議的核心部分纤掸。并將HTTP中的PUT
/GET
/POST
/DELETE
操作和對(duì)資源的insdert
/select
/updaate
/delete
操作對(duì)應(yīng)。
REST的思想是使用HTTP的命令來(lái)對(duì)數(shù)據(jù)進(jìn)行獲取和操作浑塞。REST使用URL來(lái)引用資源和相應(yīng)操作借跪。URL作為HTTP的一部分,提供了分層命名(hierachical naming)格式和參數(shù)屬性值列表(attribute-value lists)酌壕。
REST不是RPC掏愁,但有一個(gè)類(lèi)似的請(qǐng)求-響應(yīng)模型。生成請(qǐng)求卵牍、消息生成和解析響應(yīng)不是REST的一部分果港。但是REST對(duì)面向資源的服務(wù)很有意義,例如使用HTTP發(fā)送如下URL請(qǐng)求:
HTTP GET //www.xxxx.com/parts
返回一個(gè)包含請(qǐng)求數(shù)據(jù)的某種格式的數(shù)據(jù)結(jié)構(gòu)糊昙,如JSON:
{"data":"null"}
JSON
使用JSON作為數(shù)據(jù)格式來(lái)發(fā)送數(shù)據(jù)已經(jīng)十分流行辛掠。由于它不是二進(jìn)制數(shù)據(jù)格式,所以更適合作為HTTP消息的載體释牺。
但是JSON受JavaScript語(yǔ)言子集的限制萝衩,可表示的數(shù)據(jù)類(lèi)型不夠多,而且無(wú)法表示數(shù)據(jù)內(nèi)的復(fù)雜引用没咙,如自引用猩谊,互引用和循環(huán)引用。另外祭刚,某些語(yǔ)言具有多種JSON版本的實(shí)現(xiàn)牌捷,但在類(lèi)型影射上沒(méi)有統(tǒng)一標(biāo)準(zhǔn),存在兼容性問(wèn)題涡驮。
JSON只是一種消息傳遞格式暗甥,JSON不會(huì)嘗試提供RPC庫(kù)并支持服務(wù)發(fā)現(xiàn)、綁定捉捅、托管和垃圾回收撤防。使用JSON作為數(shù)據(jù)轉(zhuǎn)換格式的RPC成為JSON-RPC。JSON-RPC 雖然有規(guī)范锯梁,但是卻沒(méi)有統(tǒng)一的實(shí)現(xiàn)即碗。在不同語(yǔ)言中的各自實(shí)現(xiàn)存在兼容性問(wèn)題焰情,無(wú)法真正互通陌凳。
無(wú)需IDL?
JSON來(lái)源于JavaScript中的"Associative array"内舟,由于"Associative array"在弱類(lèi)型語(yǔ)言中本身就是類(lèi)的概念合敦,所以在這些弱語(yǔ)言如JavaScript、PHP中得到了良好的支持验游。并且充岛,因?yàn)镴SON中的字段一般可以和類(lèi)中的屬性名稱(chēng)和值一一對(duì)應(yīng)保檐,所以對(duì)于Java這強(qiáng)類(lèi)型語(yǔ)言可以通過(guò)反射操作統(tǒng)一轉(zhuǎn)換。
Google Protocol Buffers
Google Protocol Buffers本質(zhì)上只是一種序列化機(jī)制崔梗,并不是完整的RPC夜只。它僅僅簡(jiǎn)化了網(wǎng)絡(luò)傳輸中編組(marshaling)和解組(unmarshaling)的流程。protobuf為結(jié)構(gòu)化數(shù)據(jù)的序列化提供了一種高效的機(jī)制蒜魄,使得將數(shù)據(jù)編碼到網(wǎng)絡(luò)上并解碼接收到的數(shù)據(jù)變得容易扔亥。Protobuf定義了一種平臺(tái)獨(dú)立的數(shù)據(jù)結(jié)構(gòu)類(lèi)型,使得其序列化后的數(shù)據(jù)十分緊湊谈为,解析非常高效旅挤。與很多IDL類(lèi)似,protobuf的消息結(jié)構(gòu)以高級(jí)格式定義伞鲫,包含名稱(chēng)粘茄、類(lèi)型和值。protobuf既可用于類(lèi)似RPC的消息傳遞秕脓,也可用于持久性存儲(chǔ)柒瓣,您需要將數(shù)據(jù)轉(zhuǎn)換為標(biāo)準(zhǔn)的串行形式以將其寫(xiě)入文件。一個(gè)例子是:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
和XML相比吠架,protobuf生成的字節(jié)碼短了2.5倍嘹朗,解析速度快50倍左右。
其他常見(jiàn)的RPC框架優(yōu)缺點(diǎn)可以參考什么是RESTful诵肛?到底R(shí)EST和SOAP屹培、RPC有何區(qū)別?中其中一個(gè)回答怔檩。
文獻(xiàn)
RPC的拆解和實(shí)現(xiàn)可以查閱RPC的概念模型與實(shí)現(xiàn)解析
引用
Remote Procedure Calls - Paul Krzyzanowski
Difference Between RPC and SOAP
序列化和反序列化 - 美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì)
Api 體系架構(gòu)分享(上)