框架相關(guān)(11)-- RPC框架

RPC框架詳細(xì)內(nèi)容:
http://www.lxweimin.com/p/193634cca86a

在一個典型 RPC 的使用場景中,包含了服務(wù)發(fā)現(xiàn)、負(fù)載、容錯、網(wǎng)絡(luò)傳輸、序列化等組件,其中“RPC 協(xié)議”就指明了程序如何進(jìn)行網(wǎng)絡(luò)傳輸和序列化。

完整 RPC 架構(gòu)圖

RPC 核心功能

RPC 的核心功能是指實(shí)現(xiàn)一個 RPC 最重要的功能模塊,就是上圖中的”RPC 協(xié)議”部分:

RPC 核心功能

一個 RPC 的核心功能主要有 5 個部分組成,分別是:客戶端、客戶端 Stub、網(wǎng)絡(luò)傳輸模塊、服務(wù)端 Stub、服務(wù)端等。

RPC核心功能

下面分別介紹核心 RPC 框架的重要組成:

客戶端(Client):服務(wù)調(diào)用方。

客戶端存根(Client Stub):存放服務(wù)端地址信息,將客戶端的請求參數(shù)數(shù)據(jù)信息打包成網(wǎng)絡(luò)消息,再通過網(wǎng)絡(luò)傳輸發(fā)送給服務(wù)端。

服務(wù)端存根(Server Stub):接收客戶端發(fā)送過來的請求消息并進(jìn)行解包,然后再調(diào)用本地服務(wù)進(jìn)行處理。

服務(wù)端(Server):服務(wù)的真正提供者。

Network Service:底層傳輸,可以是 TCP 或 HTTP。

在這兩次網(wǎng)絡(luò)傳輸中使用了 HTTP 協(xié)議,建立 HTTP 協(xié)議之間有 TCP 三次握手,斷開 HTTP 協(xié)議時(shí)有 TCP 四次揮手。

RPC 調(diào)用詳細(xì)流程圖

一次 RPC 調(diào)用流程如下:

服務(wù)消費(fèi)者(Client 客戶端)通過本地調(diào)用的方式調(diào)用服務(wù)。

客戶端存根(Client Stub)接收到調(diào)用請求后負(fù)責(zé)將方法、入?yún)⒌刃畔⑿蛄谢ńM裝)成能夠進(jìn)行網(wǎng)絡(luò)傳輸?shù)南Ⅲw。

客戶端存根(Client Stub)找到遠(yuǎn)程的服務(wù)地址,并且將消息通過網(wǎng)絡(luò)發(fā)送給服務(wù)端。

服務(wù)端存根(Server Stub)收到消息后進(jìn)行解碼(反序列化操作)。

服務(wù)端存根(Server Stub)根據(jù)解碼結(jié)果調(diào)用本地的服務(wù)進(jìn)行相關(guān)處理

服務(wù)端(Server)本地服務(wù)業(yè)務(wù)處理。

處理結(jié)果返回給服務(wù)端存根(Server Stub)。

服務(wù)端存根(Server Stub)序列化結(jié)果。

服務(wù)端存根(Server Stub)將結(jié)果通過網(wǎng)絡(luò)發(fā)送至消費(fèi)方。

客戶端存根(Client Stub)接收到消息,并進(jìn)行解碼(反序列化)。

服務(wù)消費(fèi)方得到最終結(jié)果。


RPC 核心之功能實(shí)現(xiàn)

RPC 的核心功能主要由 5 個模塊組成,如果想要自己實(shí)現(xiàn)一個 RPC,最簡單的方式要實(shí)現(xiàn)三個技術(shù)點(diǎn),分別是:

服務(wù)尋址

數(shù)據(jù)流的序列化和反序列化

網(wǎng)絡(luò)傳輸

服務(wù)尋址

服務(wù)尋址可以使用 Call ID 映射。在本地調(diào)用中,函數(shù)體是直接通過函數(shù)指針來指定的,但是在遠(yuǎn)程調(diào)用中,函數(shù)指針是不行的,因?yàn)閮蓚€進(jìn)程的地址空間是完全不一樣的。

所以在 RPC 中,所有的函數(shù)都必須有自己的一個 ID。這個 ID 在所有進(jìn)程中都是唯一確定的。

客戶端在做遠(yuǎn)程過程調(diào)用時(shí),必須附上這個 ID。然后我們還需要在客戶端和服務(wù)端分別維護(hù)一個函數(shù)和Call ID的對應(yīng)表。

當(dāng)客戶端需要進(jìn)行遠(yuǎn)程調(diào)用時(shí),它就查一下這個表,找出相應(yīng)的 Call ID,然后把它傳給服務(wù)端,服務(wù)端也通過查表,來確定客戶端需要調(diào)用的函數(shù),然后執(zhí)行相應(yīng)函數(shù)的代碼。

實(shí)現(xiàn)方式:服務(wù)注冊中心。

要調(diào)用服務(wù),首先你需要一個服務(wù)注冊中心去查詢對方服務(wù)都有哪些實(shí)例。Dubbo 的服務(wù)注冊中心是可以配置的,官方推薦使用 Zookeeper。

實(shí)現(xiàn)案例:RMI(Remote Method Invocation,遠(yuǎn)程方法調(diào)用)也就是 RPC 本身的實(shí)現(xiàn)方式。

Registry(服務(wù)發(fā)現(xiàn)):借助 JNDI 發(fā)布并調(diào)用了 RMI 服務(wù)。實(shí)際上,JNDI 就是一個注冊表,服務(wù)端將服務(wù)對象放入到注冊表中,客戶端從注冊表中獲取服務(wù)對象。

RMI 服務(wù)在服務(wù)端實(shí)現(xiàn)之后需要注冊到 RMI Server 上,然后客戶端從指定的 RMI 地址上 Lookup 服務(wù),調(diào)用該服務(wù)對應(yīng)的方法即可完成遠(yuǎn)程方法調(diào)用。

Registry 是個很重要的功能,當(dāng)服務(wù)端開發(fā)完服務(wù)之后,要對外暴露,如果沒有服務(wù)注冊,則客戶端是無從調(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)成一個字節(jié)流,傳給服務(wù)端后,再把字節(jié)流轉(zhuǎn)成自己能讀取的格式。

只有二進(jìn)制數(shù)據(jù)才能在網(wǎng)絡(luò)中傳輸,序列化和反序列化的定義是:

將對象轉(zhuǎn)換成二進(jìn)制流的過程叫做序列化

將二進(jìn)制流轉(zhuǎn)換成對象的過程叫做反序列化

這個過程叫序列化和反序列化。同理,從服務(wù)端返回的值也需要序列化反序列化的過程。

網(wǎng)絡(luò)傳輸

網(wǎng)絡(luò)傳輸:遠(yuǎn)程調(diào)用往往用在網(wǎng)絡(luò)上,客戶端和服務(wù)端是通過網(wǎng)絡(luò)連接的。

所有的數(shù)據(jù)都需要通過網(wǎng)絡(luò)傳輸,因此就需要有一個網(wǎng)絡(luò)傳輸層。網(wǎng)絡(luò)傳輸層需要把 Call ID 和序列化后的參數(shù)字節(jié)流傳給服務(wù)端,然后再把序列化后的調(diào)用結(jié)果傳回客戶端。

只要能完成這兩者的,都可以作為傳輸層使用。因此,它所使用的協(xié)議其實(shí)是不限的,能完成傳輸就行。

盡管大部分 RPC 框架都使用 TCP 協(xié)議,但其實(shí) UDP 也可以,而 gRPC 干脆就用了 HTTP2。

TCP 的連接是最常見的,簡要分析基于 TCP 的連接:通常 TCP 連接可以是按需連接(需要調(diào)用的時(shí)候就先建立連接,調(diào)用結(jié)束后就立馬斷掉),也可以是長連接(客戶端和服務(wù)器建立起連接之后保持長期持有,不管此時(shí)有無數(shù)據(jù)包的發(fā)送,可以配合心跳檢測機(jī)制定期檢測建立的連接是否存活有效),多個遠(yuǎn)程過程調(diào)用共享同一個連接。

所以,要實(shí)現(xiàn)一個 RPC 框架,只需要把以下三點(diǎn)實(shí)現(xiàn)了就基本完成了:

Call ID 映射:可以直接使用函數(shù)字符串,也可以使用整數(shù) ID。映射表一般就是一個哈希表。

序列化反序列化:可以自己寫,也可以使用 Protobuf 或者 FlatBuffers 之類的。

網(wǎng)絡(luò)傳輸庫:可以自己寫 Socket,或者用 Asio,ZeroMQ,Netty 之類。

RPC 核心之網(wǎng)絡(luò)傳輸協(xié)議

在第三節(jié)中說明了要實(shí)現(xiàn)一個 RPC,需要選擇網(wǎng)絡(luò)傳輸?shù)姆绞健?/p>

網(wǎng)絡(luò)傳輸

在 RPC 中可選的網(wǎng)絡(luò)傳輸方式有多種,可以選擇 TCP 協(xié)議、UDP 協(xié)議、HTTP 協(xié)議。

每一種協(xié)議對整體的性能和效率都有不同的影響,如何選擇一個正確的網(wǎng)絡(luò)傳輸協(xié)議呢?首先要搞明白各種傳輸協(xié)議在 RPC 中的工作方式。

基于 TCP 協(xié)議的 RPC 調(diào)用

由服務(wù)的調(diào)用方與服務(wù)的提供方建立 Socket 連接,并由服務(wù)的調(diào)用方通過 Socket 將需要調(diào)用的接口名稱、方法名稱和參數(shù)序列化后傳遞給服務(wù)的提供方,服務(wù)的提供方反序列化后再利用反射調(diào)用相關(guān)的方法。

最后將結(jié)果返回給服務(wù)的調(diào)用方,整個基于 TCP 協(xié)議的 RPC 調(diào)用大致如此。

但是在實(shí)例應(yīng)用中則會進(jìn)行一系列的封裝,如 RMI 便是在 TCP 協(xié)議上傳遞可序列化的 Java 對象。

基于 HTTP 協(xié)議的 RPC 調(diào)用

該方法更像是訪問網(wǎng)頁一樣,只是它的返回結(jié)果更加單一簡單。

其大致流程為:由服務(wù)的調(diào)用者向服務(wù)的提供者發(fā)送請求,這種請求的方式可能是 GET、POST、PUT、DELETE 等中的一種,服務(wù)的提供者可能會根據(jù)不同的請求方式做出不同的處理,或者某個方法只允許某種請求方式。

而調(diào)用的具體方法則是根據(jù) URL 進(jìn)行方法調(diào)用,而方法所需要的參數(shù)可能是對服務(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é)議棧的下層,能夠更加靈活地對協(xié)議字段進(jìn)行定制,減少網(wǎng)絡(luò)開銷,提高性能,實(shí)現(xiàn)更大的吞吐量和并發(fā)數(shù)。

基于 HTTP 協(xié)議實(shí)現(xiàn)的 RPC 則可以使用 JSON 和 XML 格式的請求或響應(yīng)數(shù)據(jù)。

RabbitMQ 在 RPC 中角色

使用 RabbitMQ 的好處:

同步變異步:可以使用線程池將同步變成異步,但是缺點(diǎn)是要自己實(shí)現(xiàn)線程池,并且強(qiáng)耦合。使用消息隊(duì)列可以輕松將同步請求變成異步請求。

低內(nèi)聚高耦合:解耦,減少強(qiáng)依賴。

流量削峰:通過消息隊(duì)列設(shè)置請求最大值,超過閥值的拋棄或者轉(zhuǎn)到錯誤界面。

網(wǎng)絡(luò)通信性能提高:TCP 的創(chuàng)建和銷毀開銷大,創(chuàng)建 3 次握手,銷毀 4 次分手,高峰時(shí)成千上萬條的鏈接會造成資源的巨大浪費(fèi),而且操作系統(tǒng)每秒處理 TCP 的數(shù)量也是有數(shù)量限制的,必定造成性能瓶頸。

RabbitMQ 采用信道通信,不采用 TCP 直接通信。一條線程一條信道,多條線程多條信道,公用一個 TCP 連接。

一條 TCP 連接可以容納無限條信道(硬盤容量足夠的話),不會造成性能瓶頸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,505評論 2 379

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