什麼是Rpc框架,為什麼需要RPC框架?

Javaspring架構師


本地調用VS遠程調用

RPC:Remote Procedure Call,中文意思就是遠程過程調用。

遠程是相對於本地來說的,有遠程調用就有本地調用,那麼先說說本地調用是什麼,這個就簡單了;比如下圖,我們的代碼在同一個進程中(或者說同一個地址空間)調用另外一個方法,得到我們需要的結果,這就是本地調用:

那麼想象一下,如果這裡的add方法是一個很複雜的方法,很多系統都想用這個方法,那麼我們可以把這個方法單獨拆成一個服務,提供給各個系統進行調用,那麼本地就會變成遠程,就會變成這樣:

RPC:讓遠程調用變得和本地調用一樣

那麼在Server_A中怎麼調用Server_B中的add方法呢?很多人都會想到Server_B封裝一個接口,通過服務把這個方法暴露出去,比如Restful接口,那麼Server_A就可以調用Server_B中的add方法了。

通過這種方法實現起來沒有問題,也是一個不錯的解決方法,就是在每次調用的時候,都要發起HTTP請求,代碼裡面要寫HttpClient.sendRequest這樣的代碼,那麼我們有沒有可能像調用本地一樣,去發起遠程調用呢?讓程序員不知道這是調用的遠程方法呢?這時候就要提到RPC了:

  1. RPC用於服務之間的調用問題,特別是分佈式環境;

  2. RPC讓遠程調用時,像調用本地方法一樣方便和無感知;

  3. RPC框架屏蔽了很多底層的細節,不需要開發人員關注這些細節,比如序列化和反序列化、網絡傳輸協議的細節;

  4. 完整的RPC過程,如圖(畫的比較簡單):

當然,上文只是簡單地介紹了一下RPC的概念和優點,其實真正的RPC框架還是很複雜的,除了序列化和反序列化,客戶端中還需要有連接池管理、負載均衡、故障轉移、超時管理等功能,服務端中有上下文管理器、異步回調、收發包隊列、工作線程等等。

我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。


會點代碼的大叔


RPC是指遠程過程調用,也就是說兩臺服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的函數/方法,由於不在一個內存空間,不能直接調用,需要通過網絡來表達調用的語義和傳達調用的數據。

為什麼要用RPC呢?就是無法在一個進程內,甚至一個計算機內通過本地調用的方式完成的需求,比如不同的系統間的通訊,甚至不同的組織間的通訊,由於計算能力需要橫向擴展,需要在多臺機器組成的集群上部署應用。

RPC就是要像調用本地的函數一樣去調遠程函數。在研究RPC前,我們先看看本地調用是怎麼調的。假設我們要調用函數Multiply來計算lvalue * rvalue的結果:

1 int Multiply(int l, int r) {

2 int y = l * r;

3 return y;

4 }

5

6 int lvalue = 10;

7 int rvalue = 20;

8 int l_times_r = Multiply(lvalue, rvalue);

那麼在第8行時,我們實際上執行了以下操作:

將 lvalue 和 rvalue 的值壓棧

進入Multiply函數,取出棧中的值10 和 20,將其賦予 l 和 r

執行第2行代碼,計算 l * r ,並將結果存在 y

將 y 的值壓棧,然後從Multiply返回

第8行,從棧中取出返回值 200 ,並賦值給 l_times_r

以上5步就是執行本地調用的過程。

在遠程調用時,我們需要執行的函數體是在遠程的機器上的,也就是說,Multiply是在另一個進程中執行的。這就帶來了幾個新問題:

Call ID映射。我們怎麼告訴遠程機器我們要調用Multiply,而不是Add或者FooBar呢?在本地調用中,函數體是直接通過函數指針來指定的,我們調用Multiply,編譯器就自動幫我們調用它相應的函數指針。但是在遠程調用中,函數指針是不行的,因為兩個進程的地址空間是完全不一樣的。所以,在RPC中,所有的函數都必須有自己的一個ID。這個ID在所有進程中都是唯一確定的。客戶端在做遠程過程調用時,必須附上這個ID。然後我們還需要在客戶端和服務端分別維護一個 {函數 Call ID} 的對應表。兩者的表不一定需要完全相同,但相同的函數對應的Call ID必須相同。當客戶端需要進行遠程調用時,它就查一下這個表,找出相應的Call ID,然後把它傳給服務端,服務端也通過查表,來確定客戶端需要調用的函數,然後執行相應函數的代碼。序列化和反序列化。客戶端怎麼把參數值傳給遠程的函數呢?在本地調用中,我們只需要把參數壓到棧裡,然後讓函數自己去棧裡讀就行。但是在遠程過程調用時,客戶端跟服務端是不同的進程,不能通過內存來傳遞參數。甚至有時候客戶端和服務端使用的都不是同一種語言(比如服務端用C++,客戶端用Java或者Python)。這時候就需要客戶端把參數先轉成一個字節流,傳給服務端後,再把字節流轉成自己能讀取的格式。這個過程叫序列化和反序列化。同理,從服務端返回的值也需要序列化反序列化的過程。網絡傳輸。遠程調用往往用在網絡上,客戶端和服務端是通過網絡連接的。所有的數據都需要通過網絡傳輸,因此就需要有一個網絡傳輸層。網絡傳輸層需要把Call ID和序列化後的參數字節流傳給服務端,然後再把序列化後的調用結果傳回客戶端。只要能完成這兩者的,都可以作為傳輸層使用。因此,它所使用的協議其實是不限的,能完成傳輸就行。儘管大部分RPC框架都使用TCP協議,但其實UDP也可以,而gRPC乾脆就用了HTTP2。Java的Netty也屬於這層的東西。

常用的RPC框架包括 thrift



白話壹與零


http協議,也是一種“rpc”協議。


分享到:


相關文章: