什么是RPC?
- RPC全稱Remote Procedure Call譯為遠(yuǎn)程過程調(diào)用
- RPC是一個計算機(jī)通信協(xié)議,允許調(diào)用不同進(jìn)程空間的程序。
- RPC允許跨機(jī)器、跨語言調(diào)用計算機(jī)程序方法。
- RPC的客戶端和服務(wù)器可以在一臺機(jī)器上甘邀,也可以在不同的機(jī)器上。
程序員使用RPC時,就像調(diào)用本地程序一樣,無需關(guān)注內(nèi)部的實現(xiàn)細(xì)節(jié)。運行于一臺計算機(jī)的程序調(diào)用另一臺計算機(jī)的子程序檀轨,程序員無需額外地為交互作用編程。RPC允許開發(fā)者直接調(diào)用另一臺計算機(jī)上的程序,開發(fā)者無需額外地為這個調(diào)用過程編寫網(wǎng)絡(luò)通信相關(guān)代碼,使得開發(fā)包括網(wǎng)絡(luò)分布式程序在內(nèi)的應(yīng)用程序更加容易歪玲。
為什么需要RPC框架?
- 分布式系統(tǒng)中服務(wù)之間的調(diào)用問題
- 遠(yuǎn)程過程調(diào)用要能夠像本地調(diào)用一樣顽决,讓調(diào)用者感知不到遠(yuǎn)程調(diào)用的邏輯。
如何實現(xiàn)客戶端到服務(wù)端的調(diào)用导匣,想要在網(wǎng)絡(luò)中任意兩臺計算機(jī)上實現(xiàn)遠(yuǎn)程過程調(diào)用擎值,需要解決很多問題。
- 兩臺物理機(jī)在網(wǎng)絡(luò)中需要建立穩(wěn)定且可靠的通信連接
- 兩臺服務(wù)器的通信協(xié)議定義問題逐抑,兩臺服務(wù)器程序如何識別對方的請求和返回結(jié)果鸠儿。
- 兩臺計算機(jī)必須都能夠識別對方發(fā)送過來的信息,并且能夠識別出其中的請求含義和返回含義厕氨,才能進(jìn)行處理进每。
RPC框架
RPC框架需要解決什么問題?
- 傳輸協(xié)議
- 報文編碼格式
- 可用性問題
在兩臺機(jī)器上兩個應(yīng)用程序之間需要通信時命斧,首先需要確定采用的傳輸協(xié)議是什么田晚?如果兩個應(yīng)用程序位于不同的機(jī)器,一般會選擇TCP或HTTP国葬。如果兩個應(yīng)用程序位于相同的機(jī)器贤徒,也可選擇UNIX Socket。
傳輸協(xié)議確定后汇四,還需確定報文的編碼格式接奈,比如采用最常用的JSON或XML,若文本較大可能會選擇Protobuf等其它編碼方式通孽,甚至編碼后再進(jìn)行壓縮序宦。接收方獲取報文則需要先解壓再解碼。
解決了傳輸協(xié)議和報文編碼問題后背苦,接下來需要解決一系列的可用性問題互捌。比如,連接超時了怎么辦行剂?是否支持異步請求和并發(fā)秕噪?
如果服務(wù)端實例很多,而客戶端并不關(guān)心這些實例的地址和部署位置厚宰,只關(guān)心自己能夠獲取到期的結(jié)果腌巾,那就引出了注冊中心(registery)和負(fù)載均衡(load balance)的問題。簡單地說固阁,即客戶端和服務(wù)端相互不感知對方的存在壤躲,服務(wù)端啟動時將自己注冊到注冊中心,客戶端調(diào)用時备燃,從注冊中心獲取到所有可用的實例碉克,選擇一個來調(diào)用。這樣服務(wù)端和客戶端只需要感知注冊中心的存在就夠了并齐。注冊中心通常還需要實現(xiàn)服務(wù)動態(tài)添加漏麦、刪除客税,使用心跳確保服務(wù)處于可用狀態(tài)等功能。
再進(jìn)一步撕贞,假設(shè)服務(wù)端是不同的團(tuán)隊提供的更耻,如果沒有統(tǒng)一的RPC框架,各個團(tuán)隊的服務(wù)提供方就需要各自實現(xiàn)一套消息編碼解碼捏膨、連接池秧均、收發(fā)線程、超時處理等“業(yè)務(wù)之外”的重復(fù)技術(shù)勞動号涯,造成整體的抵消目胡。因此“業(yè)務(wù)之外”的這部分公共的能力,即RPC框架所需具備的能力链快。
傳輸協(xié)議
RPC本質(zhì)上是一種協(xié)議誉己,允許一臺計算機(jī)程序通過網(wǎng)絡(luò)從遠(yuǎn)程計算機(jī)程序上請求服務(wù),無需使用者了解底層網(wǎng)絡(luò)技術(shù)域蜗。RPC協(xié)議構(gòu)建在TCP巨双、UDP、HTTP之上霉祸,在OSI七層網(wǎng)絡(luò)通信模型中筑累,RPC跨域了傳輸層和應(yīng)用層,使網(wǎng)絡(luò)分布式程序開發(fā)更為容易脉执。
RPC采用C/S(客戶端/服務(wù)器)的工作模式疼阔,請求程序為客戶端(client),服務(wù)提供程序為服務(wù)端(server)半夷。當(dāng)執(zhí)行一個遠(yuǎn)程過程調(diào)用時,客戶端程序首先會發(fā)送一個帶有參數(shù)的調(diào)用信息服務(wù)端迅细,然后等待服務(wù)端響應(yīng)巫橄。
- 客戶端調(diào)用句柄發(fā)送參數(shù),調(diào)用本地系統(tǒng)內(nèi)核茵典,發(fā)送網(wǎng)絡(luò)消息到服務(wù)端等待應(yīng)答湘换。
- 服務(wù)端句柄接收到調(diào)用信息,獲得進(jìn)程參數(shù)统阿,執(zhí)行遠(yuǎn)程過程彩倚,計算結(jié)果,返回服務(wù)端句柄扶平。
- 服務(wù)端句柄返回響應(yīng)帆离,調(diào)用遠(yuǎn)程系統(tǒng)內(nèi)核,將消息傳回本地结澄。
- 客戶端句柄從本地主機(jī)內(nèi)核中接收數(shù)據(jù)后哥谷,客戶端接收句柄返回的數(shù)據(jù)岸夯。
在服務(wù)端,服務(wù)進(jìn)程保持休眠狀態(tài)直到客戶端調(diào)用信息到達(dá)為止们妥,當(dāng)一個調(diào)用信息到達(dá)時猜扮,服務(wù)端獲得進(jìn)程參數(shù),計算出結(jié)果监婶,并向客戶端發(fā)送應(yīng)答信息旅赢,然后等待下一個調(diào)用。最后惑惶,客戶端接收來自服務(wù)端的應(yīng)答信息鲜漩,獲得進(jìn)程結(jié)果,然后調(diào)用執(zhí)行并繼續(xù)集惋。
RPC架構(gòu)
RPC在架構(gòu)上由四部分組成:客戶端(client)孕似、客戶端存根(client stub)、服務(wù)端(server)刮刑、服務(wù)端存根(server stub)
- 客戶端
服務(wù)調(diào)用發(fā)起方喉祭,又稱為服務(wù)消費者。 - 客戶端存根
客戶端存根程序運行在客戶端所在的計算機(jī)上雷绢,主要用來存儲要調(diào)用的服務(wù)端的地址泛烙。
客戶端存根程序負(fù)責(zé)將客戶端請求遠(yuǎn)端服務(wù)端程序的數(shù)據(jù)打包成為數(shù)據(jù)包,通過網(wǎng)絡(luò)發(fā)送給服務(wù)端存根程序翘紊。
客戶端存根接收服務(wù)端存根程序發(fā)送的調(diào)用結(jié)果數(shù)據(jù)包蔽氨,并解析返回給客戶端。 - 服務(wù)端
遠(yuǎn)端的計算機(jī)機(jī)器上運行的程序帆疟,擁有客戶端需要調(diào)用的方法鹉究。 - 服務(wù)端存根
服務(wù)端存根接受客戶端存根程序通過網(wǎng)絡(luò)發(fā)送的請求消息數(shù)據(jù)包,并調(diào)用服務(wù)端中真正的程序功能方法踪宠,完成功能調(diào)用自赔。
服務(wù)端存根將服務(wù)端執(zhí)行調(diào)用的結(jié)果進(jìn)行數(shù)據(jù)處理打包后發(fā)送給客戶端存根程序。
RPC是如何實現(xiàn)遠(yuǎn)程過程調(diào)用的的呢柳琢?
1.當(dāng)客戶端發(fā)起一個遠(yuǎn)程過程調(diào)用時绍妨,首先調(diào)用本地客戶端存根程序的方式調(diào)用想要使用的功能方法名。
2.客戶端存根程序接收到客戶端的功能調(diào)用請求后柬脸,將客戶端請求調(diào)用的方法名他去、攜帶的參數(shù)等信息進(jìn)行序列化,然后打包成數(shù)據(jù)包倒堕。
3.客戶端存根查找到遠(yuǎn)程服務(wù)端程序的IP地址后灾测,調(diào)用Socket通信協(xié)議,通過網(wǎng)絡(luò)發(fā)送給服務(wù)端涩馆。
4.服務(wù)端存根程序接收到客戶端發(fā)送的數(shù)據(jù)包信息行施,通過約定好的協(xié)議將數(shù)據(jù)反序列化允坚,得到請求的方法名和請求參數(shù)等參數(shù)。
5.服務(wù)端存根程序準(zhǔn)備相關(guān)數(shù)據(jù)后蛾号,調(diào)用本地服務(wù)端對應(yīng)的功能方法稠项,傳入對應(yīng)參數(shù)。
6.服務(wù)端程序根據(jù)已有業(yè)務(wù)邏輯執(zhí)行調(diào)用過程鲜结,等到業(yè)務(wù)執(zhí)行結(jié)束后展运,將執(zhí)行結(jié)果返回給服務(wù)端存根程序。
7.服務(wù)端存根程序?qū)⒊绦蛘{(diào)用結(jié)果按照約定的協(xié)議進(jìn)行序列化后精刷,通過網(wǎng)絡(luò)發(fā)送給客戶端存根程序拗胜。
8.客戶端存根程序接收到服務(wù)端存根程序發(fā)送的返回數(shù)據(jù)后,對數(shù)據(jù)進(jìn)行反序列化操作怒允,并將調(diào)用返回的數(shù)據(jù)傳遞給客戶端請求發(fā)起者埂软。
9.客戶端請求發(fā)起者得到調(diào)用結(jié)果,整個RPC調(diào)用過程結(jié)束纫事。
RPC相關(guān)技術(shù)
1.動態(tài)代理技術(shù)
服務(wù)端存根程序和客戶端存根程序勘畔,在具體編碼實現(xiàn)中會使用動態(tài)代理技術(shù)自動生成一段程序。
2.序列化和反序列化
RPC調(diào)用過程中丽惶,數(shù)據(jù)需從一臺機(jī)器上傳遞給另外一臺機(jī)器上炫七。互聯(lián)網(wǎng)上所有數(shù)據(jù)都是以字節(jié)的形式進(jìn)行傳輸钾唬,在編碼過程中往往使用的都是數(shù)據(jù)對象万哪,要在互聯(lián)網(wǎng)上傳遞數(shù)據(jù)對象和變量,需要對數(shù)據(jù)對象做序列化和反序列化處理抡秆。
- 序列化:將對象轉(zhuǎn)換為字節(jié)序列的過程成為對象的序列化奕巍,即編碼的過程。
- 反序列化:將字節(jié)序列恢復(fù)為對象的過程稱為對象的反序列化琅轧,即解碼的過程伍绳。
報文編碼格式
Golang中實現(xiàn)RPC會使用已經(jīng)封裝好的官方庫和第三方庫。Go RPC可以利用TCP或HTTP來傳遞數(shù)據(jù)乍桂,對要傳遞的數(shù)據(jù)使用多種類型的編碼解碼方案。
- net/rpc
Golang官方提供的net/rpc
庫使用encoding/gob
進(jìn)行編碼和解碼效床,支持TCP和HTTP數(shù)據(jù)傳輸方式睹酌,由于其他語言不支持Golang特有的gob
編碼方式,因此使用net/rpc
庫實現(xiàn)的RPC無法跨語言調(diào)用剩檀。
- net/rpc/jsonrpc
Golang官方還提供了net/rpc/jsonrpc
庫實現(xiàn)RPC方式憋沿,JSON RPC采用JSON進(jìn)行數(shù)據(jù)編碼和解碼,因而支持跨語言調(diào)用沪猴,但目前jsonrpc
庫是基于TCP協(xié)議實現(xiàn)的辐啄,不支持HTTP采章。
- protobuf
除了Golang官方提供的RPC庫,第三方庫大部分會采用protobuf
進(jìn)行數(shù)據(jù)編碼和解碼壶辜,根據(jù)protobuf
聲明文件可自動生成RPC方法與服務(wù)注冊代碼悯舟,在Golang中可以很方便地進(jìn)行RPC服務(wù)調(diào)用。