遠(yuǎn)程過(guò)程調(diào)用及其發(fā)展

遠(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
RPC

圖片來(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)用碱茁。在這之間的步驟大概如下裸卫。

  1. 客戶(hù)端調(diào)用client stub中的過(guò)程(procedure),因?yàn)?code>client stub部署在客戶(hù)端纽竣,所以調(diào)用起來(lái)和調(diào)用本地方法看上去是一樣的墓贿。
  2. 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ù)組穴吹。
  3. 通過(guò)使用Socket接口對(duì)本地內(nèi)核進(jìn)行系統(tǒng)調(diào)用幽勒,client stub將網(wǎng)絡(luò)消息發(fā)送到遠(yuǎn)程系統(tǒng)。
  4. 網(wǎng)絡(luò)消息由內(nèi)核通過(guò)某種協(xié)議(例如無(wú)連接的UDP港令,面向連接的TCP)傳輸?shù)竭h(yuǎn)程系統(tǒng)啥容。
  5. skeleton對(duì)來(lái)自消息的參數(shù)進(jìn)行解包裝,將它們從標(biāo)準(zhǔn)網(wǎng)絡(luò)格式轉(zhuǎn)換成特定于機(jī)器的形式顷霹。
  6. skeleton使用這些參數(shù)調(diào)用server端的函數(shù)或者方法(對(duì)客戶(hù)端來(lái)說(shuō)即遠(yuǎn)程過(guò)程)干毅。
  7. skeleton獲取返回結(jié)果,并重新包裝泼返、編組為消息發(fā)送回客戶(hù)端硝逢。
  8. 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
Stub

由于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ì):序列化和反序列化
圖片來(lái)自美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì):序列化和反序列化

接口描述語(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)分享(上)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末褪秀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子薛训,更是在濱河造成了極大的恐慌媒吗,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乙埃,死亡現(xiàn)場(chǎng)離奇詭異闸英,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)介袜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)甫何,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人遇伞,你說(shuō)我怎么就攤上這事辙喂。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵巍耗,是天一觀的道長(zhǎng)秋麸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)炬太,這世上最難降的妖魔是什么灸蟆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮亲族,結(jié)果婚禮上次乓,老公的妹妹穿的比我還像新娘寥茫。我一直安慰自己望艺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布封救。 她就那樣靜靜地躺著女气,像睡著了一般杏慰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炼鞠,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天缘滥,我揣著相機(jī)與錄音,去河邊找鬼谒主。 笑死朝扼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的霎肯。 我是一名探鬼主播擎颖,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼观游!你這毒婦竟也來(lái)了搂捧?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤懂缕,失蹤者是張志新(化名)和其女友劉穎允跑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搪柑,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡聋丝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了工碾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弱睦。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倚喂,靈堂內(nèi)的尸體忽然破棺而出每篷,到底是詐尸還是另有隱情,我是刑警寧澤端圈,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布焦读,位于F島的核電站,受9級(jí)特大地震影響舱权,放射性物質(zhì)發(fā)生泄漏矗晃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一宴倍、第九天 我趴在偏房一處隱蔽的房頂上張望张症。 院中可真熱鬧,春花似錦鸵贬、人聲如沸俗他。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)兆衅。三九已至,卻和暖如春嗜浮,著一層夾襖步出監(jiān)牢的瞬間羡亩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工危融, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留畏铆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓吉殃,卻偏偏與公主長(zhǎng)得像辞居,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛋勺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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

  • 轉(zhuǎn)自:http://blog.csdn.net/kesonyk/article/details/50924489 ...
    晴天哥_王志閱讀 24,808評(píng)論 2 38
  • 在分布式服務(wù)框架中速侈,一個(gè)最基礎(chǔ)的問(wèn)題就是遠(yuǎn)程服務(wù)是怎么通訊的,在Java領(lǐng)域中有很多可實(shí)現(xiàn)遠(yuǎn)程通訊的技術(shù)迫卢,例如:R...
    wyatt_plus閱讀 830評(píng)論 0 4
  • #打卡# 07月14日 周五 天氣晴轉(zhuǎn)雷陣雨 身體狀態(tài)9分 【我的進(jìn)度】每日5點(diǎn)35分(爭(zhēng)取5點(diǎn))前早起第311...
    龍馬行天下閱讀 242評(píng)論 0 2
  • 剛剛乾蛤,有風(fēng)從耳邊吹過(guò)每界,騎著小毛驢從鎮(zhèn)里穿過(guò)。 我準(zhǔn)備回家家卖。 1年前眨层、私は先生と一緒に日本へ行きました。 つまり上荡、そ...
    風(fēng)啟笙閱讀 180評(píng)論 0 0
  • 早晨趴樱,家鄉(xiāng)二十年前后照片勾起了一段童年馒闷,沉浸當(dāng)下,信手小記: 破敗陳舊的磚磚瓦瓦 常青長(zhǎng)情的草草木木 珍藏童年的歡...
    那年楓紅閱讀 228評(píng)論 2 7