RPC(遠端過程呼叫)詳解

每天进步多一点發表於2024-04-27

一、RPC是什麼

RPC是指遠端過程呼叫,也就是說兩臺伺服器A,B,一個應用部署在A伺服器上,想要呼叫B伺服器上應用提供的函式/方法,由於不在一個記憶體空間,不能直接呼叫,需要透過網路來表達呼叫的語義和傳達呼叫的資料。

二、RPC需要解決的問題

1、Call ID對映

我們怎麼告訴遠端機器我們要呼叫funA,而不是funB或者funC呢?在本地呼叫中,函式體是直接透過函式指標來指定的,我們呼叫funA,編譯器就自動幫我們呼叫它相應的函式指標。但是在遠端呼叫中,函式指標是不行的,因為兩個程序的地址空間是完全不一樣的。

所以,在RPC中,所有的函式都必須有自己的一個ID。這個ID在所有程序中都是唯一確定的。客戶端在做遠端過程呼叫時,必須附上這個ID。然後我們還需要在客戶端和服務端分別維護一個 {函式 <–> Call ID} 的對應表。兩者的表不一定需要完全相同,但相同的函式對應的Call ID必須相同。

【Note】當客戶端需要進行遠端呼叫時,它就查一下這個表,找出相應的Call ID,然後把它傳給服務端,服務端也透過查表,來確定客戶端需要呼叫的函式,然後執行相應函式的程式碼。

2、序列化和反序列化

客戶端怎麼把引數值傳給遠端的函式呢?在本地呼叫中,我們只需要把引數壓到棧裡,然後讓函式自己去棧裡讀就行。

但是在遠端過程呼叫時,客戶端跟服務端是不同的程序,不能透過記憶體來傳遞引數。甚至有時候客戶端和服務端使用的都不是同一種語言(比如服務端用C++,客戶端用Java或者Python)。

【Note】這時候就需要客戶端把引數先轉成一個位元組流(編碼),傳給服務端後,再把位元組流轉成自己能讀取的格式(解碼)。這個過程叫序列化和反序列化。同理,從服務端返回的值也需要序列化反序列化的過程。

3、網路傳輸

遠端呼叫往往用在網路上,客戶端和服務端是透過網路連線的。所有的資料都需要透過網路傳輸,因此就需要有一個網路傳輸層。

【Note】網路傳輸層需要把Call ID和序列化後的引數位元組流傳給服務端,然後再把序列化後的呼叫結果傳回客戶端。只要能完成這兩者的,都可以作為傳輸層使用。因此,它所使用的協議其實是不限的,能完成傳輸就行。儘管大部分RPC框架都使用TCP協議,但其實UDP也可以,而gRPC乾脆就用了HTTP2。

所以,要實現一個RPC框架,其實只需要把以上三點實現了就基本完成了。Call ID對映可以直接使用函式字串,也可以使用整數ID。對映表一般就是一個雜湊表。序列化反序列化可以自己寫,也可以使用Protobuf或者FlatBuffers之類的。網路傳輸庫可以自己寫socket,或者用asio,ZeroMQ,Netty之類。

4、RPC的呼叫流程圖

三、常用的RPC框架

  • gRPC是Google公佈的開源軟體,基於最新的HTTP2.0協議,並支援常見的眾多程式語言。我們知道HTTP2.0是基於二進位制的HTTP協議升級版本,目前各大瀏覽器都在快馬加鞭的加以支援。這個RPC框架是基於HTTP協議實現的,底層使用到了Netty框架的支援。
  • Thrift是Facebook的一個開源專案,主要是一個跨語言的服務開發框架。它有一個程式碼生成器來對它所定義的IDL定義檔案自動生成服務程式碼框架。使用者只要在其之前進行二次開發就行,對於底層的RPC通訊等都是透明的。不過這個對於使用者來說的話需要學習特定領域語言這個特性,還是有一定成本的。
  • Dubbo是阿里集團開源的一個極為出名的RPC框架,在很多網際網路公司和企業應用中廣泛使用。協議和序列化框架都可以插拔是及其鮮明的特色。同樣的遠端介面是基於Java Interface,並且依託於spring框架方便開發。可以方便的打包成單一檔案,獨立程序執行,和現在的微服務概念一致。

相關文章