RPC框架及選型

1. RPC 概述

http://dubbo.apache.org/zh-cn/docs/user/references/protocol/dubbo.html (以dubbo為例)

1.1 什么是RPC

RPC(Remote Procedure Call Protocol)遠(yuǎn)程過程調(diào)用協(xié)議:
它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請求服務(wù)疲陕,而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議误辑。
簡言之,RPC使得程序能夠像訪問本地系統(tǒng)資源一樣,去訪問遠(yuǎn)端系統(tǒng)資源津畸。
比較關(guān)鍵的一些方面包括:
通訊協(xié)議疏咐、序列化、資源(接口)描述洒嗤、服務(wù)框架院尔、性能蜻展、語言支持等。

#簡單的說
RPC就是從一臺機(jī)器(客戶端)上通過參數(shù)傳遞的方式調(diào)用 --> 
另一臺機(jī)器(服務(wù)器)上的一個函數(shù)或方法(可以統(tǒng)稱為服務(wù)) --> 
并得到返回的結(jié)果邀摆。

RPC 調(diào)用的分類

#從調(diào)用過程來看纵顾,可以分為同步通信RPC和異步通信RPC
>> 同步調(diào)用:客戶端等待調(diào)用執(zhí)行完成并獲取到執(zhí)行結(jié)果。
>> 異步調(diào)用:客戶端調(diào)用后不用等待執(zhí)行結(jié)果返回栋盹,但依然可以通過回調(diào)通知等方式獲取返回結(jié)果施逾。
若客戶端不關(guān)心調(diào)用返回結(jié)果,則變成單向異步調(diào)用例获,單向調(diào)用不用返回結(jié)果汉额。
異步和同步的區(qū)分在于是否等待服務(wù)端執(zhí)行完成并返回結(jié)果。

#從是否跨平臺可分為
單語言 RPC榨汤,如 RMI, Remoting蠕搜;
跨平臺 RPC,如 google protobuffer, restful json收壕,http XML妓灌。

#從通信協(xié)議層面可以分為
基于 HTTP 協(xié)議的 RPC;
基于二進(jìn)制協(xié)議的 RPC蜜宪;
基于 TCP 協(xié)議的 RPC虫埂。

1.2 RPC協(xié)議

在一個典型的RPC的使用場景中,
包含了服務(wù)發(fā)現(xiàn)圃验、負(fù)載掉伏、容錯、序列化和網(wǎng)絡(luò)傳輸?shù)冉M件澳窑,
其中RPC協(xié)議指明了程序如何進(jìn)行序列化和網(wǎng)絡(luò)傳輸斧散,
也就是說一個RPC協(xié)議的實(shí)現(xiàn)等于一個非透明的RPC調(diào)用。

簡單來說照捡,分布式框架的核心是RPC框架颅湘,RPC框架的核心是RPC協(xié)議。
RPC協(xié)議在RPC調(diào)用中的位置.png

RPC協(xié)議的基本組成

>> IP:服務(wù)提供者的地址
>> 端口:協(xié)議指定開放端口
>> 運(yùn)行服務(wù)
(1)netty
(2)mima
(3)rmi
(4)servlet容器(Jetty栗精、Tomcat闯参、Jboss)
>> 協(xié)議報(bào)文編解碼
>> 序列化方式
(1)Hessian2Serialization
(2)DubboSerialization
(3)JavaSerialization
(4)JsonSerialization
RPC協(xié)議的基本組成.png

RPC消息協(xié)議

#消息邊界

RPC 需要在一條 TCP 鏈接上進(jìn)行屢次消息傳遞。
在連續(xù)的兩條消息之間必需有明確的分割規(guī)則悲立,以便接收端可以將消息分割開來鹿寨,
這里的接收端可以是 RPC 服務(wù)器接收請求,也可以是 RPC 用戶端接收響應(yīng)薪夕。

基于 TCP 鏈接之上的單條消息假如過大脚草,就會被網(wǎng)絡(luò)協(xié)議棧拆分為多個數(shù)據(jù)包進(jìn)行傳送。
假如消息過小原献,網(wǎng)絡(luò)協(xié)議椓罂可能會將多個消息組合成一個數(shù)據(jù)包進(jìn)行發(fā)送埂淮。
對于接收端來說它看到的只是一串串的字節(jié)數(shù)組,假如沒有明確的消息邊界規(guī)則写隶,
接收端是無從知道這一串字節(jié)數(shù)組到底是包含多條消息還是只是某條消息的一部分倔撞。

#比較常使用的兩種分割方式是特殊分割符法和長度前綴法。
>> 特殊分割符法
消息發(fā)送端在每條消息的末尾追加一個特殊的分割符慕趴,并且保證消息中間的數(shù)據(jù)不能包含特殊分割符痪蝇。
比方最為常見的分割符是 \r\n 。當(dāng)接收端遍歷字節(jié)數(shù)組時發(fā)現(xiàn)了 冕房,
就立就可以斷定之前的字節(jié)數(shù)組是一條完整的消息躏啰,可以傳遞到上層邏輯繼續(xù)進(jìn)行解決。
HTTP 和 Redis 協(xié)議就大量用了 分割符耙册。
此種消息一般要求消息體的內(nèi)容是"文本消息"给僵。
>> 長度前綴法
消息發(fā)送端在每條消息的開頭添加一個 4 字節(jié)長度的整數(shù)值,標(biāo)記消息體的長度觅玻。
這樣消息接受者首先讀取到長度信息想际,而后再讀取相應(yīng)長度的字節(jié)數(shù)組即可以將一個完整的消息分離出來。
此種消息比較常使用于"二進(jìn)制消息"溪厘。

#比較
#特殊分割符法
優(yōu)點(diǎn): 消息的可讀性比較強(qiáng)胡本,可以直接看到消息的文本內(nèi)容
缺點(diǎn): 是不適合傳遞二進(jìn)制消息,由于二進(jìn)制的字節(jié)數(shù)組里面很容易就冒出連續(xù)的兩個字節(jié)內(nèi)容正好就是分割符的 ascii 值畸悬。
使用: 假如需要傳遞的話侧甫,一般是對二進(jìn)制進(jìn)行 base64 編碼轉(zhuǎn)變成普通文本消息再進(jìn)行傳送。

#長度前綴法
優(yōu)點(diǎn)和缺點(diǎn)同特殊分割符法正好是相反的蹋宦。
缺點(diǎn): 由于適使用于二進(jìn)制協(xié)議披粟,所以可讀性很差。
優(yōu)點(diǎn): 對傳遞的內(nèi)容本身沒有特殊限制冷冗,文本和內(nèi)容皆可以傳輸守屉,不需要進(jìn)行特殊解決。
HTTP 協(xié)議的 Content-Length 頭信息使用來標(biāo)記消息體的長度蒿辙,這個也可以看成是長度前綴法的一種應(yīng)使用拇泛。

#應(yīng)用
HTTP 協(xié)議是一種基于特殊分割符和長度前綴法的混合型協(xié)議。
比方 HTTP 的消息頭采使用的是純文本外加 分割符思灌,
而消息體則是通過消息頭中的 Content-Type 的值來決定長度俺叭。
HTTP 協(xié)議盡管被稱之為文本傳輸協(xié)議,但是也可以在消息體中傳輸二進(jìn)制數(shù)據(jù)數(shù)據(jù)的泰偿,
例如音視頻圖像熄守,所以 HTTP 協(xié)議被稱之為「超文本」傳輸協(xié)議。
消息邊界--特殊分割符法.png
消息邊界--長度前綴法.png
#消息的結(jié)構(gòu)

每條消息都有它包含的語義結(jié)構(gòu)信息,有些消息協(xié)議的結(jié)構(gòu)信息是顯式的裕照,還有些是隱式的攒发。

#顯式結(jié)構(gòu)的消息協(xié)議
比方 json 消息,它的結(jié)構(gòu)即可以直接通過它的內(nèi)容表現(xiàn)出來晋南,所以它是一種顯式結(jié)構(gòu)的消息協(xié)議晨继。
json 這種直觀的消息協(xié)議的可讀性非常棒,但是它的缺點(diǎn)也很顯著搬俊,有太多的冗余信息。
比方每個字符串都用雙引號來界定邊界蜒茄,key/value 之間必需有冒號分割唉擂,對象之間必需用大括號分割等等。
這些還只是冗余的小頭檀葛,最大的冗余還在于連續(xù)的多條 json 消息即便結(jié)構(gòu)完全一樣玩祟,
僅僅只是 value 的值不一樣,也需要發(fā)送同樣的 key 字符串信息屿聋。

>> 對顯示結(jié)構(gòu)消息協(xié)議的改進(jìn)之處
消息的結(jié)構(gòu)在同一條消息通道上是可以復(fù)使用的空扎,
比方在建立鏈接的開始 RPC 用戶端和服務(wù)器之間先交流協(xié)商一下消息的結(jié)構(gòu),
后續(xù)發(fā)送消息時只要要發(fā)送一系列消息的 value 值润讥,
接收端會自動將 value 值和相應(yīng)位置的 key 關(guān)聯(lián)起來转锈,形成一個完成的結(jié)構(gòu)消息。
在 Hadoop 系統(tǒng)中廣泛用的 avro 消息協(xié)議就是通過這種方式實(shí)現(xiàn)的楚殿,
在 RPC 鏈接建立之處就開始交流消息的結(jié)構(gòu)撮慨,后續(xù)消息的傳遞即可以節(jié)省很多流量。

#隱式結(jié)構(gòu)的消息協(xié)議
消息的隱式結(jié)構(gòu)一般是指那些結(jié)構(gòu)信息由代碼來商定的消息協(xié)議脆粥,
在 RPC 交互的消息數(shù)據(jù)中只是純粹的二進(jìn)制數(shù)據(jù)砌溺,由代碼來確定相應(yīng)位置的二進(jìn)制是屬于哪個字段。

假如純粹看消息內(nèi)容是無法知道節(jié)點(diǎn)消息內(nèi)容中的哪些字節(jié)的含義变隔,
它的消息結(jié)構(gòu)是通過代碼的結(jié)構(gòu)順序來確定的规伐。
這種隱式的消息的優(yōu)點(diǎn)就在于節(jié)省傳輸流量,它完全不需要傳輸結(jié)構(gòu)信息匣缘。
#消息壓縮

假如消息的內(nèi)容太大猖闪,就要考慮對消息進(jìn)行壓縮解決,這可以減輕網(wǎng)絡(luò)帶寬壓力孵户。
但是這同時也會加重 CPU 的負(fù)擔(dān)萧朝,由于壓縮算法是 CPU 計(jì)算密集型操作,會導(dǎo)致操作系統(tǒng)的負(fù)載加重夏哭。
所以检柬,最終能否進(jìn)行消息壓縮,肯定要根據(jù)業(yè)務(wù)情況加以權(quán)衡。

假如確定壓縮何址,那么在選擇壓縮算法包時里逆,
務(wù)必篩選那些底層使用 C 語言實(shí)現(xiàn)的算法庫,由于 Python 的字節(jié)碼執(zhí)行起來太慢了用爪。
比較流行的消息壓縮算法有 Google 的 snappy 算法原押,
它的運(yùn)行性能非常好,壓縮比例盡管不是最優(yōu)的偎血,但是離最優(yōu)的差距已經(jīng)不是很大诸衔。
阿里的 SOFA RPC 就用了 snappy 作為協(xié)議層壓縮算法。
消息的顯式結(jié)構(gòu).png
消息的隱式結(jié)構(gòu).png
#流量的極致優(yōu)化

開源的流行 RPC 消息協(xié)議往往對消息流量優(yōu)化到了極致颇玷,
它們通過這種方式來打動使用戶笨农,吸引使用戶來用它們。
比方對于一個整形數(shù)字帖渠,一般用 4 個字節(jié)來表示一個整數(shù)值谒亦。

但是經(jīng)過研究發(fā)現(xiàn),消息傳遞中大部分用的整數(shù)值都是很小的非負(fù)整數(shù)空郊,假如一律用 4 個字節(jié)來表示一個整數(shù)會很白費(fèi)份招。
所以就發(fā)明了一個類型叫變長整數(shù)varint。
數(shù)值非常小時狞甚,只要要用一個字節(jié)來存儲锁摔,數(shù)值略微大一點(diǎn)可以用 2 個字節(jié),
再大一點(diǎn)就是 3 個字節(jié)入愧,它還可以超過 4 個字節(jié)使用來表達(dá)長整形數(shù)字鄙漏。

其原理也很簡單,就是保留每個字節(jié)的最高位的 bit 來標(biāo)識能否后面還有字節(jié)棺蛛,
1 表示還有字節(jié)需要繼續(xù)讀怔蚌,0 表示到讀到當(dāng)前字節(jié)就結(jié)束。

#那假如是負(fù)數(shù)該怎樣辦呢旁赊?
-1 的 16 進(jìn)制數(shù)是 0xFFFFFFFF桦踊,假如要按照這個編碼那豈不是要 6 個字節(jié)才能存的下。
-1 也是非常常見的整數(shù)啊终畅。

于是 zigzag 編碼來了籍胯,專門使用來處理負(fù)數(shù)問題。
zigzag 編碼將整數(shù)范圍逐個映射到自然數(shù)范圍离福,而后再進(jìn)行 varint 編碼杖狼。
zigzag 將負(fù)數(shù)編碼成正奇數(shù),正數(shù)編碼成偶數(shù)妖爷。
解碼的時候遇到偶數(shù)直接除 2 就是原值蝶涩,遇到奇數(shù)就加 1 除 2 再取負(fù)就是原值。
流量的極致優(yōu)化.png

https://blog.csdn.net/snow____man/article/details/84072901

1.3 RPC的實(shí)現(xiàn)基礎(chǔ)

1、需要有非常高效的網(wǎng)絡(luò)通信绿聘,比如一般選擇Netty作為網(wǎng)絡(luò)通信框架嗽上;
2、需要有比較高效的序列化框架熄攘,比如谷歌的Protobuf序列化框架兽愤;
3、可靠的尋址方式(主要是提供服務(wù)的發(fā)現(xiàn)),比如可以使用Zookeeper來注冊服務(wù)等等挪圾;
4浅萧、如果是帶會話(狀態(tài))的RPC調(diào)用,還需要有會話和狀態(tài)保持的功能哲思;

關(guān)鍵技術(shù)

1惯殊、動態(tài)代理
生成Client Stub(客戶端存根)和Server Stub(服務(wù)端存根)的時候需要用到Java動態(tài)代理技術(shù),
可以使用JDK提供的原生的動態(tài)代理機(jī)制也殖,也可以使用開源的:CGLib代理,Javassist字節(jié)碼生成技術(shù)务热。

2忆嗜、序列化和反序列化
在網(wǎng)絡(luò)中,所有的數(shù)據(jù)都將會被轉(zhuǎn)化為字節(jié)進(jìn)行傳送崎岂,
所以為了能夠使參數(shù)對象在網(wǎng)絡(luò)中進(jìn)行傳輸捆毫,需要對這些參數(shù)進(jìn)行序列化和反序列化操作。
>> 序列化:把對象轉(zhuǎn)換為字節(jié)序列的過程稱為對象的序列化冲甘,也就是編碼的過程绩卤。
>> 反序列化:把字節(jié)序列恢復(fù)為對象的過程稱為對象的反序列化,也就是解碼的過程江醇。
目前比較高效的開源序列化框架:如Kryo濒憋、FastJson和Protobuf等。

3陶夜、NIO通信
出于并發(fā)性能的考慮凛驮,傳統(tǒng)的阻塞式 IO 顯然不太合適,因此我們需要異步的 IO条辟,即 NIO黔夭。
Java 提供了 NIO 的解決方案,Java 7 也提供了更優(yōu)秀的 NIO.2 支持羽嫡。
可以選擇Netty或者M(jìn)INA來解決NIO數(shù)據(jù)傳輸?shù)膯栴}本姥。

4、服務(wù)注冊中心
可選:Redis杭棵、Zookeeper婚惫、Consul 、Etcd。

1.4 RPC具體調(diào)用過程

1辰妙、服務(wù)消費(fèi)者(client客戶端)通過調(diào)用本地服務(wù)的方式調(diào)用需要消費(fèi)的服務(wù)鹰祸;
2、客戶端存根(client stub)接收到調(diào)用請求后負(fù)責(zé)將方法密浑、入?yún)⒌刃畔⑿蛄谢ńM裝)成能夠進(jìn)行網(wǎng)絡(luò)傳輸?shù)南Ⅲw蛙婴;
3、客戶端存根(client stub)找到遠(yuǎn)程的服務(wù)地址尔破,并且將消息通過網(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ù)執(zhí)行具體業(yè)務(wù)邏輯并將處理結(jié)果返回給服務(wù)端存根(server stub)絮姆;
7、服務(wù)端存根(server stub)將返回結(jié)果重新打包成消息(序列化)并通過網(wǎng)絡(luò)發(fā)送至消費(fèi)方秩霍;
8篙悯、客戶端存根(client stub)接收到消息,并進(jìn)行解碼(反序列化)铃绒;
9鸽照、服務(wù)消費(fèi)方得到最終結(jié)果;

而RPC框架的實(shí)現(xiàn)目標(biāo)則是將上面的各步完好地封裝起來颠悬,
也就是把調(diào)用矮燎、編碼/解碼的過程給封裝起來,
讓用戶感覺上像調(diào)用本地服務(wù)一樣的調(diào)用遠(yuǎn)程服務(wù)赔癌。

#更進(jìn)一步的解釋為:
>> RPC 服務(wù)方通過 RpcServer 去導(dǎo)出(export)遠(yuǎn)程接口方法诞外,
客戶方通過RpcClient 去引入(import)遠(yuǎn)程接口方法。 
>> 客戶方像調(diào)用本地方法一樣去調(diào)用遠(yuǎn)程接口方法灾票,
RPC 框架提供接口的代理實(shí)現(xiàn)浅乔,實(shí)際的調(diào)用將委托給代理 RpcProxy 。
>> 代理封裝調(diào)用信息并將調(diào)用轉(zhuǎn)交給 RpcInvoker 去實(shí)際執(zhí)行铝条。 
>> 在客戶端的 RpcInvoker 通過連接器 RpcConnector 去維持與服務(wù)端的通道 RpcChannel靖苇, 
并使用 RpcProtocol 執(zhí)行協(xié)議編碼(encode)并將編碼后的請求消息通過通道發(fā)送給服務(wù)方。
>> RPC 服務(wù)端接收器 RpcAcceptor 接收客戶端的調(diào)用請求班缰,同樣使用 RpcProtocol 執(zhí)行協(xié)議解碼(decode)贤壁。 
>> 解碼后的調(diào)用信息傳遞給 RpcProcessor 去控制處理調(diào)用過程
>> 最后再委托調(diào)用給 RpcInvoker 去實(shí)際執(zhí)行并返回調(diào)用結(jié)果。

#通過上述分析可知埠忘,這里面包括以下核心組件:
1脾拆、RpcServer
負(fù)責(zé)導(dǎo)出(export)遠(yuǎn)程接口
2馒索、RpcClient
負(fù)責(zé)導(dǎo)入(import)遠(yuǎn)程接口的代理實(shí)現(xiàn)
3、RpcProxy
遠(yuǎn)程接口的代理實(shí)現(xiàn)
4名船、RpcInvoker
客戶方實(shí)現(xiàn):負(fù)責(zé)編碼調(diào)用信息和發(fā)送調(diào)用請求到服務(wù)方并等待調(diào)用結(jié)果返回
服務(wù)方實(shí)現(xiàn):負(fù)責(zé)調(diào)用服務(wù)端接口的具體實(shí)現(xiàn)并返回調(diào)用結(jié)果
5绰上、RpcProtocol
負(fù)責(zé)協(xié)議編/解碼
6、RpcConnector
負(fù)責(zé)維持客戶方和服務(wù)方的連接通道和發(fā)送數(shù)據(jù)到服務(wù)方
7渠驼、RpcAcceptor
負(fù)責(zé)接收客戶方請求并返回請求結(jié)果
8蜈块、RpcProcessor
負(fù)責(zé)在服務(wù)方控制調(diào)用過程,包括管理調(diào)用線程池迷扇、超時時間等
9百揭、RpcChannel
數(shù)據(jù)傳輸通道
RPC的實(shí)現(xiàn)原理架構(gòu)圖1.png
RPC的實(shí)現(xiàn)原理架構(gòu)圖2.png
RPC結(jié)構(gòu).png

舉例說明

比如說,A服務(wù)器想調(diào)用B服務(wù)器上的一個方法:User getUserByName(String userName)

#1蜓席、建立通信
首先要解決通訊的問題:
即A機(jī)器想要調(diào)用B機(jī)器器一,首先得建立起通信連接。
主要是通過在客戶端和服務(wù)器之間建立TCP連接厨内,遠(yuǎn)程過程調(diào)用的所有交換的數(shù)據(jù)都在這個連接里傳輸祈秕。
通常這個連接可以是按需連接(需要調(diào)用的時候就先建立連接,調(diào)用結(jié)束后就立馬斷掉)雏胃,
也可以是長連接(客戶端和服務(wù)器建立起連接之后保持長期持有踢步,不管此時有無數(shù)據(jù)包的發(fā)送,
可以配合心跳檢測機(jī)制定期檢測建立的連接是否存活有效)丑掺,多個遠(yuǎn)程過程調(diào)用共享同一個連接。

#2述雾、服務(wù)尋址
要解決尋址的問題街州,也就是說,A服務(wù)器上的應(yīng)用怎么告訴底層的RPC框架玻孟,
如何連接到B服務(wù)器(如主機(jī)或IP地址)以及特定的端口唆缴,方法的名稱名稱是什么。
通常情況下我們需要提供B機(jī)器(主機(jī)名或IP地址)以及特定的端口黍翎,
然后指定調(diào)用的方法或者函數(shù)的名稱以及入?yún)⒊鰠⒌刃畔⒚婊眨@樣才能完成服務(wù)的一個調(diào)用∠坏В可
靠的尋址方式(主要是提供服務(wù)的發(fā)現(xiàn))是RPC的實(shí)現(xiàn)基石趟紊,比如可以采用Redis或者Zookeeper來注冊服務(wù)等等。
#2.1碰酝、從服務(wù)提供者的角度看:
當(dāng)服務(wù)提供者啟動的時候霎匈,需要將自己提供的服務(wù)注冊到指定的注冊中心,
以便服務(wù)消費(fèi)者能夠通過服務(wù)注冊中心進(jìn)行查找送爸;
當(dāng)服務(wù)提供者由于各種原因致使提供的服務(wù)停止時铛嘱,需要向注冊中心注銷停止的服務(wù)暖释;
服務(wù)的提供者需要定期向服務(wù)注冊中心發(fā)送心跳檢測,
服務(wù)注冊中心如果一段時間未收到來自服務(wù)提供者的心跳后墨吓,
認(rèn)為該服務(wù)提供者已經(jīng)停止服務(wù)球匕,則將該服務(wù)從注冊中心上去掉。
#2.2帖烘、從調(diào)用者的角度看:
服務(wù)的調(diào)用者啟動的時候根據(jù)自己訂閱的服務(wù)向服務(wù)注冊中心查找服務(wù)提供者的地址等信息亮曹;
當(dāng)服務(wù)調(diào)用者消費(fèi)的服務(wù)上線或者下線的時候,注冊中心會告知該服務(wù)的調(diào)用者蚓让;
服務(wù)調(diào)用者下線的時候乾忱,則取消訂閱。

#3历极、網(wǎng)絡(luò)傳輸
#3.1窄瘟、序列化
當(dāng)A機(jī)器上的應(yīng)用發(fā)起一個RPC調(diào)用時,
調(diào)用方法和其入?yún)⒌刃畔⑿枰ㄟ^底層的網(wǎng)絡(luò)協(xié)議如TCP傳輸?shù)紹機(jī)器趟卸,由于網(wǎng)絡(luò)協(xié)議是基于二進(jìn)制的蹄葱,
所以我們傳輸?shù)膮?shù)數(shù)據(jù)都需要先進(jìn)行序列化(Serialize)或者編組(marshal)成二進(jìn)制的形式才能在網(wǎng)絡(luò)中進(jìn)行傳輸。
然后通過尋址操作和網(wǎng)絡(luò)傳輸將序列化或者編組之后的二進(jìn)制數(shù)據(jù)發(fā)送給B機(jī)器锄列。
#3.2图云、反序列化
當(dāng)B機(jī)器接收到A機(jī)器的應(yīng)用發(fā)來的請求之后,又需要對接收到的參數(shù)等信息進(jìn)行反序列化操作(序列化的逆操作)邻邮,
即將二進(jìn)制信息恢復(fù)為內(nèi)存中的表達(dá)方式竣况,然后再找到對應(yīng)的方法(尋址的一部分)
進(jìn)行本地調(diào)用(一般是通過生成代理Proxy去調(diào)用,通常會有JDK動態(tài)代理、CGLIB動態(tài)代理筒严、
Javassist生成字節(jié)碼技術(shù)等)丹泉,之后得到調(diào)用的返回值。

#4鸭蛙、服務(wù)調(diào)用
B機(jī)器進(jìn)行本地調(diào)用(通過代理Proxy和反射調(diào)用)之后得到了返回值摹恨,
此時還需要再把返回值發(fā)送回A機(jī)器,同樣也需要經(jīng)過序列化操作娶视,
然后再經(jīng)過網(wǎng)絡(luò)傳輸將二進(jìn)制數(shù)據(jù)發(fā)送回A機(jī)器晒哄,
而當(dāng)A機(jī)器接收到這些返回值之后,則再次進(jìn)行反序列化操作肪获,恢復(fù)為內(nèi)存中的表達(dá)方式寝凌,
最后再交給A機(jī)器上的應(yīng)用進(jìn)行相關(guān)處理(一般是業(yè)務(wù)邏輯處理操作)。

通常孝赫,經(jīng)過以上四個步驟之后硫兰,一次完整的RPC調(diào)用算是完成了,
另外可能因?yàn)榫W(wǎng)絡(luò)抖動等原因需要重試等寒锚。

2.主流RPC框架有哪些

1劫映、RMI
利用java.rmi包實(shí)現(xiàn)违孝,基于Java遠(yuǎn)程方法協(xié)議(Java Remote Method Protocol) 和java的原生序列化。

2泳赋、Hessian
是一個輕量級的remoting onhttp工具雌桑,使用簡單的方法提供了RMI的功能。 
基于HTTP協(xié)議祖今,采用二進(jìn)制編解碼校坑。

3、protobuf-rpc-pro
是一個Java類庫千诬,提供了基于 Google 的 Protocol Buffers 協(xié)議的遠(yuǎn)程方法調(diào)用的框架耍目。
基于 Netty 底層的 NIO 技術(shù)。
支持 TCP 重用/ keep-alive徐绑、SSL加密邪驮、RPC 調(diào)用取消操作、嵌入式日志等功能傲茄。

4毅访、Apache Thrift
是一種可伸縮的跨語言服務(wù)的軟件框架。
它擁有功能強(qiáng)大的代碼生成引擎盘榨,無縫地支持C + +喻粹,C#,Java草巡,Python和PHP和Ruby守呜。
Thrift允許你定義一個描述文件,描述數(shù)據(jù)類型和服務(wù)接口山憨。
依據(jù)該文件查乒,編譯器方便地生成RPC客戶端和服務(wù)器通信代碼。
最初由facebook開發(fā)用做系統(tǒng)內(nèi)個語言之間的RPC通信萍歉,
2007年由facebook貢獻(xiàn)到apache基金 ,現(xiàn)在是apache下的opensource之一 档桃。
支持多種語言之間的RPC方式的通信, 底層通訊基于SOCKET枪孩。

5、Avro
出自Hadoop之父Doug Cutting, 
在Thrift已經(jīng)相當(dāng)流行的情況下推出Avro的目標(biāo)不僅是提供一套類似Thrift的通訊中間件,
更是要建立一個新的藻肄,標(biāo)準(zhǔn)性的云計(jì)算的數(shù)據(jù)交換和存儲的Protocol蔑舞。
支持HTTP,TCP兩種協(xié)議嘹屯。

6攻询、Dubbo
Dubbo是 阿里巴巴公司開源的一個高性能優(yōu)秀的服務(wù)框架,
使得應(yīng)用可通過高性能的 RPC 實(shí)現(xiàn)服務(wù)的輸出和輸入功能州弟,可以和 Spring框架無縫集成钧栖。

7低零、Motan
新浪微博內(nèi)部RPC框架。

2.1 跟語言平臺綁定的開源 RPC 框架

>> Dubbo:
國內(nèi)最早開源的 RPC 框架拯杠,由阿里巴巴公司開發(fā)并于 2011 年末對外開源掏婶,僅支持 Java 語言。
>> Motan:
微博內(nèi)部使用的 RPC 框架潭陪,于 2016 年對外開源雄妥,僅支持 Java 語言。
>> Tars:
騰訊內(nèi)部使用的 RPC 框架依溯,于 2017 年對外開源老厌,僅支持 C++ 語言。
>> Spring Cloud:
國外 Pivotal 公司 2014 年對外開源的 RPC 框架黎炉,僅支持 Java 語言枝秤。

2.1.1 Dubbo

http://www.reibang.com/p/49a675abcad0 (參考該文)

2.1.2 Motan

https://github.com/weibocom/motan/wiki (參考官方wiki)

Motan 是國內(nèi)另外一個比較有名的開源的 RPC 框架,同樣也只支持 Java 語言實(shí)現(xiàn)拜隧。

Motan 與 Dubbo 的架構(gòu)類似宿百,都需要在 Client 端(服務(wù)消費(fèi)者)和 Server 端(服務(wù)提供者)引入 SDK,
其中 Motan 框架主要包含下面幾個功能模塊洪添。
>> register:
用來和注冊中心交互垦页,包括注冊服務(wù)、訂閱服務(wù)干奢、服務(wù)變更通知痊焊、服務(wù)心跳發(fā)送等功能。
Server 端會在系統(tǒng)初始化時通過 register 模塊注冊服務(wù)忿峻,
Client 端會在系統(tǒng)初始化時通過 register 模塊訂閱到具體提供服務(wù)的 Server 列表薄啥,
當(dāng) Server 列表發(fā)生變更時也由 register 模塊通知 Client。
>> protocol:
用來進(jìn)行 RPC 服務(wù)的描述和 RPC 服務(wù)的配置管理逛尚,
這一層還可以添加不同功能的 filter 用來完成統(tǒng)計(jì)垄惧、并發(fā)限制等功能。
>> serialize:
將 RPC 請求中的參數(shù)、結(jié)果等對象進(jìn)行序列化與反序列化起愈,
即進(jìn)行對象與字節(jié)流的互相轉(zhuǎn)換骆姐,默認(rèn)使用對 Java 更友好的 Hessian 2 進(jìn)行序列化。
>> transport:
用來進(jìn)行遠(yuǎn)程通信觉壶,默認(rèn)使用 Netty NIO 的 TCP 長鏈接方式。
>> cluster:
Client 端使用的模塊件缸,cluster 是一組可用的 Server 在邏輯上的封裝铜靶,
包含若干可以提供 RPC 服務(wù)的 Server,
實(shí)際請求時會根據(jù)不同的高可用與負(fù)載均衡策略選擇一個可用的 Server 發(fā)起遠(yuǎn)程調(diào)用他炊。
Motan架構(gòu)圖.png

2.1.3 Spring Cloud

Spring Cloud 是為了解決微服務(wù)架構(gòu)中服務(wù)治理而提供的一系列功能的開發(fā)框架争剿,
它是完全基于 Spring Boot 進(jìn)行開發(fā)的已艰,Spring Cloud 利用 Spring Boot 特性整合了開源行業(yè)中優(yōu)秀的組件,
整體對外提供了一套在微服務(wù)架構(gòu)中服務(wù)治理的解決方案秒梅。
只支持 Java 語言平臺旗芬。
Spring-Cloud架構(gòu)圖.png

2.2 跨語言平臺的開源 RPC 框架

>> gRPC:
Google 于 2015 年對外開源的跨語言 RPC 框架,支持常用的 
C++捆蜀、Java疮丛、Python、Go辆它、Ruby誊薄、PHP、Android Java锰茉、Objective-C 等多種語言呢蔫。
>> Thrift:
最初是由 Facebook 開發(fā)的內(nèi)部系統(tǒng)跨語言的 RPC 框架,2007 年貢獻(xiàn)給了 Apache 基金飒筑,
成為 Apache 開源項(xiàng)目之一片吊,支持常用的 C++、Java协屡、PHP俏脊、Python、Ruby肤晓、Erlang 等多種語言爷贫。

2.2.1 gRPC

gRPC,它的原理是通過 IDL(Interface Definition Language)文件定義服務(wù)接口的參數(shù)和返回值類型补憾,
然后通過代碼生成程序生成服務(wù)端和客戶端的具體實(shí)現(xiàn)代碼漫萄,這樣在 gRPC 里,
客戶端應(yīng)用可以像調(diào)用本地對象一樣調(diào)用另一臺服務(wù)器上對應(yīng)的方法盈匾。

#它的主要特性包括三個方面
>> 通信協(xié)議采用了 HTTP/2腾务,因?yàn)?HTTP/2 提供了連接復(fù)用、雙向流削饵、服務(wù)器推送岩瘦、
請求優(yōu)先級、首部壓縮等機(jī)制葵孤,所以在通信過程中可以節(jié)省帶寬担钮、降低 TCP 連接次數(shù)橱赠、
節(jié)省 CPU尤仍,尤其對于移動端應(yīng)用來說,可以幫助延長電池壽命狭姨。
>> IDL 使用了ProtoBuf宰啦,ProtoBuf 是由 Google 開發(fā)的一種數(shù)據(jù)序列化協(xié)議苏遥,
它的壓縮和傳輸效率極高,語法也簡單赡模,所以被廣泛應(yīng)用在數(shù)據(jù)存儲和通信協(xié)議上田炭。
>> 多語言支持,能夠基于多種語言自動生成對應(yīng)語言的客戶端和服務(wù)端的代碼漓柑。
gRPC.png

2.2.2 Thrift

Thrift 是一種輕量級的跨語言 RPC 通信方案教硫,支持多達(dá) 25 種編程語言。
為了支持多種語言辆布,跟 gRPC 一樣瞬矩,Thrift 也有一套自己的接口定義語言 IDL,
可以通過代碼生成器锋玲,生成各種編程語言的 Client 端和 Server 端的 SDK 代碼景用,
這樣就保證了不同語言之間可以相互通信。

#Thrift RPC 框架的特性惭蹂。
>> 支持多種序列化格式:如 Binary伞插、Compact、JSON盾碗、Multiplexed 等媚污。
>> 支持多種通信方式:如 Socket、Framed置尔、File杠步、Memory、zlib 等榜轿。
>> 服務(wù)端支持多種處理方式:如 Simple 幽歼、Thread Pool、Non-Blocking 等谬盐。

https://github.com/apache/thrift/raw/master/doc/images/thrift-layers.png

2.n 總結(jié)

從長遠(yuǎn)來看甸私,支持多語言是 RPC 框架未來的發(fā)展趨勢。
正是基于此判斷飞傀,各個 RPC 框架都提供了 Sidecar 組件來支持多語言平臺之間的 RPC 調(diào)用皇型。
>> Dubbo 在重啟了維護(hù),并且宣稱要引入 Sidecar 組件來構(gòu)建Dubbo Mesh提供多語言支持砸烦。
>> Motan 也在去年對外開源了其內(nèi)部的 Sidecar 組件:
Motan-go弃鸦,目前支持 PHP、Java 語言之間的相互調(diào)用幢痘。
>> Spring Cloud 也提供了 Sidecar 組件 spring-cloud-netflix-sideca唬格,
可以讓其他語言也可以使用 Spring Cloud 的組件。

所以未來語言不會成為使用上面這幾種 RPC 框架的約束,
而 gRPC 和 Thrift 雖然支持跨語言的 RPC 調(diào)用购岗,但是因?yàn)樗鼈冎惶峁┝俗罨镜?RPC 框架功能汰聋,
缺乏一系列配套的服務(wù)化組件和服務(wù)治理功能的支撐,所以使用它們作為跨語言調(diào)用的 RPC 框架喊积,
就需要自己考慮注冊中心烹困、熔斷、限流乾吻、監(jiān)控髓梅、分布式追蹤等功能的實(shí)現(xiàn)。
不過好在大多數(shù)功能都有開源實(shí)現(xiàn)绎签,可以直接采用女淑。

參考資源
http://www.reibang.com/p/bbaf6af8c01f (RPC解析)
http://www.reibang.com/p/f2b8e0b11f73 (RPC框架選型參考)
https://www.cnblogs.com/wangkc/p/10864937.html (RPC與HTTP比較)
https://www.songma.com/news/txtlist_i3460v.html (RPC協(xié)議構(gòu)成)
https://blog.csdn.net/nyyjs/article/details/77850523 (RPC調(diào)用中的反射技術(shù))
http://www.360doc.com/content/18/0531/07/36490684_758407718.shtml (RPC調(diào)用中的反射技術(shù))
http://www.reibang.com/p/f4f789846fde (RPC調(diào)用過程詳解)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辜御,隨后出現(xiàn)的幾起案子鸭你,更是在濱河造成了極大的恐慌,老刑警劉巖擒权,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袱巨,死亡現(xiàn)場離奇詭異,居然都是意外死亡碳抄,警方通過查閱死者的電腦和手機(jī)愉老,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剖效,“玉大人嫉入,你說我怎么就攤上這事¤凳” “怎么了咒林?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長爷光。 經(jīng)常有香客問我垫竞,道長,這世上最難降的妖魔是什么蛀序? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任欢瞪,我火速辦了婚禮,結(jié)果婚禮上徐裸,老公的妹妹穿的比我還像新娘遣鼓。我一直安慰自己,他們只是感情好重贺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布骑祟。 她就那樣靜靜地躺著宫补,像睡著了一般。 火紅的嫁衣襯著肌膚如雪曾我。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天健民,我揣著相機(jī)與錄音抒巢,去河邊找鬼。 笑死秉犹,一個胖子當(dāng)著我的面吹牛蛉谜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播崇堵,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼型诚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鸳劳?” 一聲冷哼從身側(cè)響起狰贯,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赏廓,沒想到半個月后涵紊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡幔摸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年摸柄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片既忆。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡驱负,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出患雇,到底是詐尸還是另有隱情跃脊,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布苛吱,位于F島的核電站匾乓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏又谋。R本人自食惡果不足惜拼缝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望彰亥。 院中可真熱鬧咧七,春花似錦、人聲如沸任斋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瘟檩,卻和暖如春抹缕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背墨辛。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工卓研, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人睹簇。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓奏赘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親太惠。 傳聞我的和親對象是個殘疾皇子磨淌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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

  • 1.概述 七層模型五層模型四層模型應(yīng)用層表示層應(yīng)用層應(yīng)用層會話層傳輸層傳輸層傳輸層網(wǎng)絡(luò)層網(wǎng)絡(luò)層網(wǎng)絡(luò)層數(shù)據(jù)鏈路層數(shù)據(jù)...
    suxin1932閱讀 3,040評論 1 3
  • 走在黑黑的小巷里 沒有狗吠車喧 一切仿佛被時間定格 還記得曾經(jīng)的你 也是定格在這默默的世界 遠(yuǎn)方的你是否睡了 我多...
    晨曦城光閱讀 159評論 0 1
  • 與茶有緣閱讀 92評論 0 2
  • 因熱愛而學(xué)習(xí) 小女兒告訴我,她幫大女兒辦了一件大事凿渊。原來一個月前梁只,大女兒從海淘網(wǎng)上買一雙鞋子。今天快遞員打電話埃脏,因...
    漂亮的花閱讀 273評論 0 5