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

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

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

完整 RPC 架構(gòu)圖

RPC 核心功能

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

RPC 核心功能

一個(gè) RPC 的核心功能主要有 5 個(gè)部分組成匣距,分別是:客戶端面哥、客戶端 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 個(gè)模塊組成协饲,如果想要自己實(shí)現(xiàn)一個(gè) RPC畏腕,最簡單的方式要實(shí)現(xiàn)三個(gè)技術(shù)點(diǎn),分別是:

服務(wù)尋址

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

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

服務(wù)尋址

服務(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的對應(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ù)注冊中心跟啤。

要調(diào)用服務(wù),首先你需要一個(gè)服務(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 就是一個(gè)注冊表秃症,服務(wù)端將服務(wù)對象放入到注冊表中候址,客戶端從注冊表中獲取服務(wù)對象。

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

Registry 是個(gè)很重要的功能聚请,當(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)成一個(gè)字節(jié)流返帕,傳給服務(wù)端后,再把字節(jié)流轉(zhuǎn)成自己能讀取的格式篙挽。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

每一種協(xié)議對整體的性能和效率都有不同的影響夏跷,如何選擇一個(gè)正確的網(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)用方佣蓉,整個(gè)基于 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ù)不同的請求方式做出不同的處理,或者某個(gè)方法只允許某種請求方式柳譬。

而調(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 直接通信俯在。一條線程一條信道,多條線程多條信道娃惯,公用一個(gè) TCP 連接跷乐。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愕提,一起剝皮案震驚了整個(gè)濱河市馒稍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浅侨,老刑警劉巖纽谒,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異如输,居然都是意外死亡鼓黔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門不见,熙熙樓的掌柜王于貴愁眉苦臉地迎上來澳化,“玉大人,你說我怎么就攤上這事稳吮《泄龋” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵盖高,是天一觀的道長慎陵。 經(jīng)常有香客問我,道長喻奥,這世上最難降的妖魔是什么席纽? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮撞蚕,結(jié)果婚禮上润梯,老公的妹妹穿的比我還像新娘。我一直安慰自己甥厦,他們只是感情好纺铭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著刀疙,像睡著了一般舶赔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谦秧,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天竟纳,我揣著相機(jī)與錄音,去河邊找鬼疚鲤。 笑死锥累,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的集歇。 我是一名探鬼主播桶略,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了际歼?” 一聲冷哼從身側(cè)響起惶翻,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹬挺,沒想到半個(gè)月后维贺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巴帮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年溯泣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榕茧。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡垃沦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出用押,到底是詐尸還是另有隱情肢簿,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布蜻拨,位于F島的核電站池充,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缎讼。R本人自食惡果不足惜收夸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望血崭。 院中可真熱鬧卧惜,春花似錦、人聲如沸夹纫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舰讹。三九已至茅姜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間月匣,已是汗流浹背匈睁。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桶错,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓胀蛮,卻偏偏與公主長得像院刁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子粪狼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

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