天天看點

「RPC」簡述RPCrpc的架構

RPC是什麼

RPC(Remote Procedure Call)遠端過程調用協定,一種通過網絡從遠端計算機上請求服務,而不需要了解底層網絡技術的協定。RPC它假定某些協定的存在,例如TPC/UDP等,為通信程式之間攜帶資訊資料。在OSI網絡七層模型中,RPC跨越了傳輸層和應用層,RPC使得開發,包括網絡分布式多程式在内的應用程式更加容易。

過程是什麼?

過程就是業務處理、計算任務,更直白的說,就是程式,就是想調用本地方法一樣調用遠端的過程

程序間通信(IPC)是在多任務作業系統或聯網的計算機之間運作的程式和程序所采用的通信技術,IPC有兩種類型的程序間通信的方式分别是本地過程調用(LPC)和遠端過程調用(RPC)。

本地過程調用LPC

本地過程調用(LPC)用于多任務作業系統中,使同時運作的任務能夠互相會話,任務共享記憶體空間以實作任務同步和互相發送消息。

例如:完成一個本地函數的調用

int add(int x, int y){
  return x + y;
}
int a = 1;
int b = 2;
int result = add(a, b);
           

add()函數的執行流程

  1. 分别将變量a和b的值壓入棧
  1. 執行add()函數,從棧中取出a和b的值,指派給x和y。
  1. 計算x加y的值并儲存到棧中
  1. 退出add()函數将x加y的值指派給result

本地過程調用發生在同一程序中,共享記憶體區域。而RPC通信則需要跨域不同機器、不同程序,是以需要解決三個問題:函數ID(服務尋址)、資料流的序列化和反序列化、網絡傳輸

如果add()函數調用在用戶端,執行函數的函數體卻在遠端機器上,如何告知機器如何調用這個方法呢?

首先用戶端需要告訴伺服器,需要調用的函數,這裡函數和程序ID存在一個映射,用戶端遠端調用時需要檢查一下函數以找到對應的ID,然後執行函數的代碼。

用戶端需要将本地參數傳遞給遠端函數,本地調用的過程中直接壓棧即可。但在遠端調用過程中不在同一個記憶體中,無法直接傳遞參數的參數,是以需要用戶端将參數轉換為位元組流,傳遞給伺服器。伺服器再将位元組流轉換為自身能讀取的格式,這是一個序列化和反序列化的過程。

當資料準備好之後,如何進行傳輸呢?網絡傳輸層需要将調用的ID和序列化後的參數傳遞給伺服器,然後将計算好的結果序列化傳遞給用戶端。是以TCP層可以完成上述操作。那麼為什麼不使用HTTP層呢?由于HTTP在應用層中完成,整個通信的代價比較高,RPC直接基于TCP進行遠端調用,資料傳輸在傳輸層TCP完成,更加适合對效率要求比較高的場景。RPC主要依賴于用戶端和伺服器之間建立的Socket連結進行,但底層實作比REST更為複雜

遠端過程調用RPC

遠端過程調用(RPC)類似于LPC,隻是在網絡中工作,RPC開始是出現在SUN微系統公司和HP公司運作的UNIX作業系統中。

RPC的概念與技術早在1981年由Neison提出,1984年Birrel和Neison将其用于支援異構型分布式系統的通訊。Birrell的RPC模型引入存根程序(stub)作為遠端的本地代理,調用RPC運作時庫來傳遞網絡中的調用。Stub和RPC runtime屏蔽了網路所涉及的細節。特别是參數編碼與轉碼以及網絡任務的多樣性。RPC作為網絡通訊與委托計算的實作機制,在方法、協定、語義和實作上不斷發展,種類繁多,其中SUN公司和開發軟體基金會在分布式産品中所建立和使用的RPC較為典型。

RPC(Romote Procedure Call)遠端過程調用,RPC是通信協定,該協定允許運作于一台計算機的程式調用另一台計算機的子程式,開發人員無需額外為互動作用程式設計。若軟體采用面向對象程式設計,那麼RPC又稱為遠端調用或遠端方法調用。簡單來說,遠端調用協定是一種通過網絡從遠端計算機程式上請求服務,同時無需了解底層網絡技術的協定。

RPC是一種用于建構基于用戶端/伺服器(C/S)的分布式應用程式技術,調用者與被調用者可能在同一台伺服器上,也可能在由網絡連接配接的不同伺服器上。對用戶端和伺服器而言,使用RPC時網絡通信是透明的,遠端調用如何本地調用一樣簡單。簡單來說,RPC就是要像調用本地函數一樣去調用遠端函數。

RPC解決了什麼問題?

  1. 解決分布式系統中,服務之間的調用問題。
  1. 遠端調用時,能夠像本地調用一樣友善,讓調用者感覺不到遠端調用的邏輯。

為什麼需要RPC?

  1. RPC可以用HTTP協定實作,HTTP是建立在TCP之上最廣泛使用的RPC,網際網路公司往往會使用自己的私有協定,比如騰訊的JCE協定,私有協定不具備通用性,但相比HTTP協定,RPC采用二進制位元組碼傳輸,更加高效也更為安全。
  1. 業界提倡的微服務中,服務之間通信方式中RPC是其中之一,RPC可以保證不同服務之間的互相調用,即使是跨語言跨平台也不是問題,讓建構分布式系統更為容易。
  1. RPC架構都會存在服務降級、流量控制的功能,以保證服務的高可用。

RPC其實是一種技術思想而非規範或協定,常見RPC技術和架構有

  • 應用級的服務架構:阿裡的Dubbo/Dubbox、Google的gRPC、Spring Boot/Spring Clound
  • 遠端通信協定:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)
  • 通信架構:MINA、Netty

和本地調用有什麼差別

「RPC」簡述RPCrpc的架構

遠端調用,就好像異地戀一樣,隔着千山萬水

「RPC」簡述RPCrpc的架構

本地調用,就是女生就在你身邊,近水樓台先得月

遠端調用之間需要通過網絡,是以響應要慢幾個數量級,也不那麼可靠

平時寫程式中我們常常會用到函數調用,而一般的函數調用都在同一個程序内。但如果現在要求某個函數去調用另個工程裡的一個函數,該怎麼辦呢?

我最先想到的是http服務,編寫RESTful風格的url并通過http請求傳遞參數進而獲得遠端工程的響應,這個方法可以很友善的在兩個程式間保持通訊。

如A工程下的a方法調用B工程下的b方法:

「RPC」簡述RPCrpc的架構

但有沒有辦法可以向本地調用那麼暢快呢?不用在B工程下搭建http伺服器,進行建構url、序列化/反序列化資料等一系列操作,就直接了當的像下面這樣

function a() {
    ...
    B.b()
    ...
}
           

RPC模式

RPC采用用戶端/服務端的模式,通過request-response消息模式實作

「RPC」簡述RPCrpc的架構

RPC的三個過程

1:通訊協定

比如:你需要找人在國外幹活,那麼你可以直接飛過去或者打電話或者通過網際網路的形式,去找人,這個找人的過程就是通訊協定

2:尋址

既然要找人幹活,肯定要知道位址在哪,飛過去需要找到詳細位址,打電話需要知道電話号碼,網際網路需要知道IP是多少

3:資料序列化

就是說,語言需要互通,才能夠讓别人幹活,之間需要一個大家都懂的語言去交流

為什麼要使用RPC

1:服務化/微服務

2:分布式系統架構

3:服務可重用

4:系統間互動調用

RPC和其他協定的差別

RMI遠端方法調用是RPC的一種具體實作,webservice、restfull都是RPC,隻是消息的組織形式、消息協定不同

rpc與http的差別

可是rpc服務相較于http服務在網間通訊上有什麼優勢呢?

1. http服務使用HTTP協定傳輸資料,其的header會在消息中占很大比例,由于接收方不是浏覽器,是以這部分就是廢資訊,完全是在浪費帶寬。而rpc服務普遍基于TCP協定,自定義了消息格式,攜帶很少的無用資訊,具有很高效率。但2015年推出的HTTP2.0協定會對header做壓縮,故使用HTTP2.0來傳輸資料也可以接受。

2. rpc服務普遍基于TCP協定,http服務則基于HTTP協定。我們知道在計算機網絡的工業實作中一般采用4層模型,從上至下依次為:應用層,傳輸層,網絡層,鍊路層。

「RPC」簡述RPCrpc的架構

TCP協定位于傳輸層,而HTTP協定則基于TCP協定,位于應用層中。是以相較于rpc服務直接使用TCP協定包裝,http服務則需依次經過HTTP與TCP的兩次包裝,速度不言而喻。

3. rpc服務使用長連結,相較于http服務的短連結,避免大量三次握手所帶來的性能下降。

這條理由目前已沒那麼重要了,在HTTP1.0中需要keep-alive來建立長連接配接,HTTP1.1預設長連接配接,HTTP2.0支援多路複用,即一個連接配接處理多個請求,這一系列舉動在于盡量避免http服務建立連接配接時的過多握手。目前覺得這點可能不會太影響效率,并且Google的rpc架構GRPC就是基于HTTP2.0的。

從上面三點可以看出,相較于http服務,rpc服務具有更快的速度,并所需更小的帶寬。

4. rpc服務内部直接指明伺服器ip,且傳輸的資料是經過自己編碼過的,是以具有更高的安全性。可以認為采用http傳遞資訊是在講國語,而rpc則是講團隊黑話,具有更高的保密性。

5. rpc服務有許多現成的rpc架構,我們自己隻需去實作伺服器端的一些處理函數。有關讀寫網絡内容,使用傳輸協定序列化/反序列化資料,處理器調用等操作架構會自動處理,我們不必操心。并且rpc架構還封裝了錯誤重試等特性,針對服務的穩定性和可靠性都做了優化,而單純的http服務是沒有這些特性的。

到底選擇http服務或rpc服務來傳遞資料,還是要看具體工程,沒有絕對好壞之分,但rpc确實适合大型項目不同工程間的内部調用。另外說一下,在http伺服器上增加一層封裝,也就變成了rpc服務,比如Google的GRPC架構。

rpc的架構

rpc是典型的用戶端/伺服器模式,請求發起者是用戶端,而服務提供者是伺服器。用戶端與伺服器之間需要事先約定好傳輸方式與編碼協定。

個人感覺一個rpc架構逃不開四大核心元件:Client、Server、Client Stub、Server Skeleton。

1)Client:用戶端,服務的調用方

2)Server:服務端,服務的真正提供者

3)Client Stub:用戶端存根,存放有伺服器位址,其将用戶端的請求打包後通過網絡發給服務方

4)Server Skeleton:服務端存根,用于接收用戶端發來的消息,将消息解包後調用服務端本地方法,并将本地方法的傳回值打包後回複給用戶端

「RPC」簡述RPCrpc的架構

其中的存根可以了解成是接口,即需要自己編寫代碼去實作。其目的是屏蔽用戶端調用遠端主機上某個對象的過程,其提供某種方式在本地模拟遠端對象,負責接收本地方法的調用,并将請求委派給遠端的具體執行對象。

上面的這段描述可能有些繞,下面稍作解釋(A工程下的a方法調用B工程下的b方法)

「RPC」簡述RPCrpc的架構

使用rpc時,A工程為用戶端,B工程為服務端。為了使B工程下的b方法在a方法中可被調用,我們會在A工程裡為b方法搞個替身c。

「RPC」簡述RPCrpc的架構

c方法一旦被調用,其會調用用戶端的stub,stub通過網絡調用服務端的skeleton,而skeleton則調用并傳回本地b方法的執行結果。由此,a方法在調用用戶端c方法的時候,感覺上就是直接調用了遠端伺服器的b方法。

使用rpc的步驟

雖然可供選擇的rpc架構非常多,但使用的大體流程似乎都差不多:

1. 使用類似的IDL(接口描述語言)定義資料結構和接口

2. 選擇目智語言,用架構的代碼生成引擎生成rpc的用戶端,服務端,用戶端存根,服務端存根等代碼

3. 配置用戶端與伺服器,将響應用戶端請求的處理器與目标服務相綁定,也就是這個綁定過程需要開發者編寫一些代碼

RPC核心功能

RPC核心功能是指實作一個RPC最重要的功能子產品即RPC協定部分,一個RPC的核心功能主要由5部分組成分别是:用戶端、用戶端存根Stub、網絡傳輸模式、伺服器、伺服器存根Stub。

  • 用戶端:服務調用方
  • 用戶端存根:存放伺服器位址資訊,将用戶端請求參數資料打包成網絡消息,在通過網路傳輸發送給伺服器。
  • 網絡傳輸模式:底層傳輸,可以是TCP或HTTP。
  • 伺服器存根:接受用戶端發送過來的請求消息并進行解包,然後再調用本地服務進行處理。
  • 伺服器:服務的真正提供者
「RPC」簡述RPCrpc的架構

RPC技術點

實作RPC重點需要實作三個技術,分别是:服務尋址、資料流的序列化和反序列化、網絡傳輸

服務尋址

服務尋址可以使用Call ID映射,在本地調用中,函數體是直接通過函數指針來指定的,但在遠端調用中,函數指針是不行的,因為兩個程序的位址空間是完全不一樣的。是以在RPC中所有的函數都必須具有自己的ID,這個ID在所有程序中都是唯一的。

用戶端在做遠端過程調用時,必須附上這個函數ID,還需要在用戶端和服務端分别維護函數和Call ID的對應表。當用戶端需要進行遠端調用時,會差這個對應表找出對應的Call ID,然後将其傳遞給伺服器,伺服器也通過查對應表來确定用戶端需要調用的函數,最終執行相對應函數的代碼。

序列化和反序列化

用戶端如何将參數傳遞給遠端的函數呢?在本地過程調用中,隻需要将參數壓入棧,讓函數自己去棧中讀取即可。但在遠端過程調用中,用戶端跟伺服器是不同的程序,不能通過記憶體來傳遞參數。此時就需要用戶端将參數先轉換為位元組流再傳遞給伺服器,伺服器接收後再将位元組流轉換為自己能讀取的格式。而在網絡中隻有二進制資料才能傳輸,是以序列化與反序列化的定義也就是将對象轉換成二進制流的過程是序列化,将二進制轉換為對象的過程則是反序列化。

網絡傳輸

遠端調用往往使用在網絡環境中,用戶端和伺服器是通過網絡連接配接的,所有的資料都需要通過網絡傳輸,是以需要一個網絡傳輸層。網絡傳輸層需要将Call ID和序列化後的參數位元組流傳遞給伺服器,然後再将序列化後的調用結果傳回給用戶端。隻要能完成這兩個操作,都可以作為傳輸層使用。是以它所使用的網絡傳輸協定是不限的,隻要能完成傳輸即可。盡管大部分RPC架構都是用TCP協定,其實UDP也可以。

TCP連接配接是最常見的,通常TCP連接配接可以是按需連接配接,即需要調用時先建立調用後斷開。也可以是長連接配接,用戶端和伺服器建立連接配接後保持長期持有,不管此時有無資料包的發送,可以配合心跳檢測機制和定期檢測建立的連接配接是否存活有效。另外,多個遠端過程調用可以共享同一個連接配接。

簡單來說,實作一個RCP架構隻需要實作三點:

  • Call ID映射:可以直接使用函數字元串,也可以使用整數ID,映射表通常是要一個哈希表。
  • 序列化和反序列化:可使用Protobuf、FlatBuffers等之類
  • 網絡傳輸庫:可使用Socket、Asio、ZeroMQ、Netty等

RPC網絡傳輸協定

在RPC中可選的網絡傳輸方式有很多種,可選的包括TCP、UDP、HTTP,每種協定對整體的性能和效率都有不同的影響。如何選擇一個正确的網絡傳輸協定呢?

  • 基于TCP的RPC

基于TCP協定的RPC調用是由服務調用方和服務提供方建立Socket連接配接,并由服務調用方通過Socket将需要調用的接口名稱、方法名稱、參數序列化後傳遞給服務提供方,服務提供方反序列化後再利用反射調用相關的方法。最後将結果傳回給服務調用方,整個基于TCP協定的RPC調用大緻如此。

  • 基于HTTP的RPC

基于HTTP的RPC累加類似于通路網頁,隻是它傳回的結果更為單一簡單。首先由服務調用者向服務提供者發送請求,這種請求可能是GET、POST、PUT、DELETE等其中的一種,服務提供者可能會根據不同請求方式做出不同處理,或者某個方法隻允許某種請求方式。調用的具體方法則根據URL進行方法調用,方法所需參數可能是對伺服器調用方傳輸過去的XML或JSON資料解析後的結果,最後傳回JSON或XML的資料結果。

兩種方式對比

基于TCP實作的RPC由于TCP處于協定棧的下層,能夠更加靈活地對協定字段進行定制,減少網路開銷提高性能,實作更大的吞吐量和并發數。但需要更多關注底層複雜的細節,實作代價更高。同時對不同平台比如安卓、iOS等需要重新開發不同的工具包來進行請求發送和相應的解析,是以工作量大且難以快速響應和滿足使用者需求。

基于HTTP實作的RPC則可以使用JSON和XML格式的請求或響應資料,JSON和XML作為通用的格式開源解析工具已經相當成熟。但由于HTTP是上層協定,發送包含同等内容資訊傳輸所占用的位元組數會比TCP更高。

是以在同等網絡下通過HTTP傳輸相同的内容效率會比TCP要低,資訊傳輸所占的時間也會更長,雖然壓縮資料能夠減少這一差距

RPC工作原理

一次用戶端對伺服器的遠端過程調用,其内部操作可分為以下步驟:

「RPC」簡述RPCrpc的架構
「RPC」簡述RPCrpc的架構

RPC調用流程

圖中1-10序号的含義如下:

(1) Client像調用本地服務似的調用遠端服務;

(2) Client stub接收到調用後,将方法、參數序列化

(3) 用戶端通過sockets将消息發送到服務端

(4) Server stub 收到消息後進行解碼(将消息對象反序列化)

(5) Server stub 根據解碼結果調用本地的服務

(6) 本地服務執行(對于服務端來說是本地執行)并将結果傳回給Server stub

(7) Server stub将傳回結果打包成消息(将結果消息對象序列化)

(8) 服務端通過sockets将消息發送到用戶端

(9) Client stub接收到結果消息,并進行解碼(将結果消息發序列化)

(10) 用戶端得到最終結果。

基于RPC的開發在在工作中主要用的最多的一個是基于Dubbo協定相關的開發方式,其中注冊中心主要使用的是Zookeeper,還有一個就是相關的基于對應的RestFul風格的接口在,相關的開發的過程中,需要針對相關的功能子產品開發,在後續的開發過程中,其中在進行相關的開發的時候,針對具體的RPC調用還是比較簡單的,基本的@Feign或者走Dubbo都是可以進行開發的