RPC 是一種方便的網路通訊程式設計模型,由於和程式語言的高度結合,大大減少了處理網路資料的複雜度,讓程式碼可讀性也有可觀的提高。但是 RPC 本身的構成卻比較複雜,由於受到程式語言、網路模型、使用習慣的約束,有大量的妥協和取捨之處。
RPC 框架的討論一直是各個技術交流群中的熱點話題,例如阿里的 dubbo、新浪微博的 motan、谷歌的 grpc 以及不久前螞蟻金服開源的 sofa 都是比較出名的 RPC 框架。
認識 RPC(遠端呼叫)
我們在各種作業系統、程式語言生態圈中,多少都會接觸過“遠端呼叫”的概念。一般來說,它們指的是用一行簡單的程式碼,通過網路呼叫另外一個計算機上的某段程式。比如:
-
RMI(Remote Method Invoke):呼叫遠端的方法,“方法”一般是附屬於某個物件上的,所以通常 RMI 指對在遠端的計算機上的某個物件,進行其方法函數的呼叫。
-
RPC(Remote Procedure Call):遠端過程呼叫,指的是對網路上另外一個計算機上的,某段特定的函數程式碼的呼叫。
遠端呼叫本身是網路通訊的一種概念,它的特點是把網路通訊封裝成一個類似函數的呼叫。網路通訊在遠端呼叫外,一般還有其他的幾種概念:封包處理、訊息佇列、流過濾、資源拉取等待,它們的差異如下表所示:
方案 |
程式設計方式 |
資訊封裝 |
傳輸模型 |
典型應用 |
遠端呼叫 |
呼叫函數、輸入引數、獲得返回值 |
使用程式語言的變數、型別、函數 |
發出請求、獲得響應 |
Java RMI |
封包處理 |
呼叫 Send()/Recv(),使用位元組碼資料、編解碼、處理內容 |
把通訊內容構造成二進位制的協定包 |
傳送/接收 |
UDP 程式設計 |
訊息佇列 |
呼叫 Put()/Get(),使用“包”物件,處理其包含的內容 |
訊息被封裝成語言可用的物件或結構 |
對某佇列存入一個訊息或取出一個訊息 |
ActiveMQ |
流過濾 |
讀取一個流或寫出一個流,對流中的單元包即刻處理 |
單元長度很小的統一資料結構 |
連線、傳送/接收、處理 |
網路視訊 |
資源拉取 |
輸入一個資源 ID,獲得資源內容 |
請求或響應都包含:頭部和正文 |
請求後等待響應 |
WWW |
遠端呼叫的優勢
1) 遮蔽了網路層
因此在傳輸協定和編碼協定上,我們可以選擇不同的方案。比如 WebService 方案就是用的 HTTP 傳輸協定 +SOAP 編碼協定,而 REST 的方案往往使用 HTTP+JSON 協定。
Facebook 的 Thrift 可以客製化任何不同的傳輸協定和編碼協定,可以用 TCP+Google Protocol Buffer 也可以用 UDP+JSON 等。
由於遮蔽了網路層,可以根據實際需要來獨立的優化網路部分,而無需涉及業務邏輯的處理程式碼,這對於需要在各種網路環境下執行的程式來說,非常有價值。
2) 函數對映協定
可以直接用程式語言來書寫資料結構和函數定義,取代編寫大量的編碼協定格式和分包處理邏輯。對於那些業務邏輯非常複雜的系統,比如網路遊戲,可以節省大量定義訊息格式的時間。
函數呼叫模型非常容易學習,不需要學習通訊協定和流程,讓經驗較淺的程式設計師也能很容易的開始使用網路程式設計。
遠端呼叫的缺點
1) 增加了效能消耗
由於把網路通訊包裝成“函數”,需要大量額外的處理,比如需要預生產程式碼,或者使用反射機制。這些都是額外消耗 CPU 和記憶體的操作。而且為了表達複雜的資料型別,比如變長的型別 string/map/list,這些都要封包中增加更多的描述性資訊,則會占用更多的網路包長度。
2) 不必要的複雜化
如果是為了某些特定的業務需求,比如傳送一個固定的檔案,那麼應該用 HTTP/FTP 協定模型;如果為了做監控或者 IM 軟體,用簡單的訊息編碼收發會更快速高效;如果是為了做代理伺服器,用流式的處理會很簡單。另外,如果要做資料廣播,那麼訊息佇列會很容易做到,而遠端呼叫這幾乎無法完成。
因此,遠端呼叫最適合是業務需求多變或者網路環境多變的場景。
RPC 結構拆解
RPC 的結構如下圖所示:
圖:RPC 結構圖