理解 RPC

1. 什麼是 rpc

RPC 全稱爲 Remote Procedure Call,翻譯過來爲 “遠程過程調用”。

目前,主流的平臺中都支持各種遠程調用技術,以滿足分佈式系統架構中不同的系統之間的遠程通信和相互調用。遠程調用的應用場景極其廣泛,實現的方式也各式各樣。

2. 從通信協議的層面

基於 HTTP 協議的(例如基於文本的 SOAP(XML)、Rest(JSON),基於二進制 Hessian(Binary))

基於 TCP 協議的(通常會藉助 Mina、Netty 等高性能網絡框架)

RPC (遠程過程調用) 是什麼

  • 簡單的說,RPC 就是從一臺機器(客戶端)上通過參數傳遞的方式調用另一臺機器(服務器)上的一個函數或方法(可以統稱爲服務)並得到返回的結果。

  • RPC 會隱藏底層的通訊細節(不需要直接處理 Socket 通訊或 Http 通訊)

  • RPC 是一個請求響應模型。客戶端發起請求,服務器返回響應(類似於 Http 的工作方式)

  • RPC 在使用形式上像調用本地函數(或方法)一樣去調用遠程的函數(或方法)。

遠程過程調用發展歷程

  • ONC RPC (開放網絡計算的遠程過程調用),OSF RPC(開放軟件基金會的遠程過程調用)

  • CORBA(Common Object Request Broker Architecture 公共對象請求代理體系結構)

  • DCOM(分佈式組件對象模型),COM+

  • Java RMI

  • .NET Remoting

  • XML-RPC,SOAP,Web Service

  • PHPRPC,Hessian,JSON-RPC

  • Microsoft WCF,WebAPI

  • ZeroC Ice,Thrift,GRPC

  • Hprose

早期的 RPC

  • 第一代 RPC(ONC RPC,OSF RPC)不支持對象的傳遞。

  • CORBA 太複雜,各種不同實現不兼容,一般程序員也玩不轉。

  • DCOM,COM+ 逃不出 Windows 的手掌心。

  • RMI 只能在 Java 裏面玩。

  • .NET Remoting 只能在 .NET 平臺上玩。

XML-RPC,SOAP,WebService

  • 冗餘數據太多,處理速度太慢。

  • RPC 風格的 Web Service 跨語言性不佳,而 Document 風格的 Web Service 又太過難用。

  • Web Service 沒有解決用戶的真正問題,只是把一個問題變成了另一個問題。

  • Web Service 的規範太過複雜,以至於在 .NET 和 Java 平臺以外沒有真正好用的實現,甚至沒有可用的實現。

  • 跨語言跨平臺只是 Web Service 的一個口號,雖然很多人迷信這一點,但事實上它並沒有真正實現。

PHPRPC

  • 基於 PHP 內置的序列化格式,在跨語言的類型映射上存在硬傷。

  • 通訊上依賴於 HTTP 協議,沒有其它底層通訊方式的選擇。

  • 內置的加密傳輸既是特點,也是缺點。

  • 雖然比基於 XML 的 RPC 速度快,但還不是足夠快。

Hessian

  • 二進制的數據格式完全不具有可讀性。

  • 官方只提供了兩個半語言的實現(Java,ActionScript 和不怎麼完美的 Python 實現),其它語言的第三方實現良莠不齊。

  • 支持的語言不夠多,對 Web 前端的 JavaScript 完全無視。

  • 雖然是動態 RPC,但動態性仍然欠佳。

  • 雖然比基於 XML 的 RPC 速度快,但還不是足夠快。

JSON-RPC

  • JSON 具有文本可讀性,且比 XML 更簡潔。

  • JSON 受 JavaScript 語言子集的限制,可表示的數據類型不夠多。

  • JSON 格式無法表示數據內的自引用,互引用和循環引用。

  • 某些語言具有多種版本的實現,但在類型影射上沒有統一標準,存在兼容性問題。

  • JSON-RPC 雖然有規範,但是卻沒有統一的實現。在不同語言中的各自實現存在兼容性問題,無法真正互通。

Microsoft WCF,WebAPI

  • 它們是微軟對已有技術的一個 .NET 平臺上的統一封裝,是對 .NET Remoting、WebService 和基於 JSON 、XML 等數據格式的 REST 風格的服務等技術的一個整合。

  • 雖然號稱可以在 .NET 平臺以外來調用它的這些服務,但實際上跟在 .NET 平臺內調用完全是兩碼事。它沒有提供任何在其他平臺的語言中可以使用的任何工具。

ZeroC Ice,Thrift,GRPC

  • 初代 RPC 技術的跨語言面向對象的迴歸。

  • 仍然需要通過中間語言來編寫類型和接口定義。

  • 仍然需要用代碼生成器來將中間語言編寫的類型和接口定義翻譯成你所使用的編程語言的客戶端和服務器端的佔位程序(stub)。

  • 你必須要基於生成的服務器代碼來單獨編寫服務,而不能將已有代碼直接作爲服務發佈。

  • 你必須要用生成的客戶端代碼來調用服務,而沒有其它更靈活的方式。

  • 如果你的中間代碼做了修改,以上所有步驟你都要至少重複一遍。

Hprose

  • 無侵入式設計,不需要單獨定義類型,不需要單獨編寫服務,已有代碼可以直接發佈爲服務。

  • 具有豐富的數據類型和完美的跨語言類型映射,支持自引用,互引用和循環引用數據。

  • 支持衆多傳輸方式,如 HTTP、TCP、Websocket 等。

  • 客戶端具有更靈活的調用方式,支持同步調用,異步調用,動態參數,可變參數,引用參數傳遞,多結果返回(Golang)等語言特徵,Hprose 2.0 甚至支持推送。

  • 具有良好的可擴展性,可以通過過濾器和中間件實現加密、壓縮、緩存、代理等各種功能性擴展。

  • 兼容的無差別跨語言調用

  • 支持更多的常用語言和平臺

  • 支持瀏覽器端的跨域調用

  • 沒有中間語言,無需學習成本

  • 性能卓越,使用簡單

RPC 與 Socket 有什麼區別?

兩者都是調用遠程的方法,都是 client/server 模式。

RPC(遠程過程調用)採用客戶機 / 服務器模式實現兩個進程之間相互通信。socket 是 RPC 經常採用的通信手段之一,RPC 是在 Socket 的基礎上實現的,它比 socket 需要更多的網絡和系統資源。除了 Socket,RPC 還有其他的通信方法,比如:http、操作系統自帶的管道等技術來實現對於遠程程序的調用。微軟的 Windows 系統中,RPC 就是採用命名管道進行通信。

RPC 與 REST 有什麼區別?

通過了解 RPC 後,我們知道是 RPC 是 client/server 模式的,調用遠程的方法,REST 也是我們熟悉的一套 API 調用協議方法,它也是基於 client/server 模式的,調用遠程的方法的,那他倆又有啥區別呢?

REST API 和 RPC 都是在 Server 端 把一個個函數封裝成接口暴露出去,以供 Client 端 調用,不過 REST API 是基於 HTTP 協議的,REST 致力於通過 http 協議中的 POST/GET/PUT/DELETE 等方法和一個可讀性強的 URL 來提供一個 http 請求。而 RPC 則可以不基於 HTTP 協議

因此,如果是後端兩種語言互相調用,用 RPC 可以獲得更好的性能(省去了 HTTP 報頭等一系列東西),應該也更容易配置。如果是前端通過 AJAX 調用後端,那麼用 REST API 的形式比較好(因爲無論如何也避不開 HTTP 這道坎)。

1、HTTP 和 RPC 同一級別,還是被 RPC 包含?

2、Restful 也屬於 RPC 麼?

上圖是一個比較完整的關係圖,這時我們發現 HTTP(圖中藍色框)出現了兩次。其中一個是和 RPC 並列的,都是跨應用調用方法的解決方案;另一個則是被 RPC 包含的,是 RPC 通信過程的可選協議之一。

 

因此,第一個問題的答案是都對。看指的是哪一個藍色框。從題主的提問看,既然題主在糾結這兩者,應該是指與 RPC 並列的藍色框。

第二個問題是在問遠程過程調用(紅色框)是不是包含了 Restful(黃色框),這種理解的關鍵在於對 RPC 的理解。

RPC 字面理解是遠程過程調用,即在一個應用中調用另一個應用的方法。那 Restful 是滿足的,通過它可以實現在一個應用中調用另一個應用的方法。

但是,上述理解使得 RPC 的定義過於寬泛。RPC 通常特指在一個應用中調用另一個應用的接口而實現的遠程調用,即紅色框所指的範圍。這樣,RPC 是不包含 Restful 的。

因此,第二個問題的答案是 Restful 不屬於 RPC,除非對 RPC 有着非常規的寬泛理解。

RPC 的英文全稱是 Remote Procedure Call,翻譯爲中文叫 “遠程過程調用”。其中稍顯晦澀的其實就是 “過程”,過程其實就是方法。所以,可以把 RPC 理解爲 “遠程方法調用”。

要了解遠程過程調用,那先理解過程調用。非常簡單,如下圖,就是調用一個方法。這太常見了,不多解釋。

 

 

而在分佈式系統中,因爲每個服務的邊界都很小,很有可能調用別的服務提供的方法。這就出現了服務 A 調用服務 B 中方法的需求,即遠程過程調用。

要想讓服務 A 調用服務 B 中的方法,最先想到的就是通過 HTTP 請求實現。是的,這是很常見的,例如服務 B 暴露 Restful 接口,然後讓服務 A 調用它的接口。基於 Restful 的調用方式因爲可讀性好(服務 B 暴露出的是 Restful 接口,可讀性當然好)而且 HTTP 請求可以通過各種防火牆,因此非常不錯。

然而,如前面所述,基於 Restful 的遠程過程調用有着明顯的缺點,主要是效率低、封裝調用複雜。當存在大量的服務間調用時,這些缺點變得更爲突出。

服務 A 調用服務 B 的過程是應用間的內部過程,犧牲可讀性提升效率、易用性是可取的。基於這種思路,RPC 產生了。

通過 hprose 實現 rpc

HPROSE 是 High Performance Remote Object Service Engine 的縮寫,翻譯成中文就是 “高性能遠程對象服務引擎”。

它是一個先進的輕量級的跨語言跨平臺面向對象的高性能遠程動態通訊中間件。它不僅簡單易用,而且功能強大。你只需要稍許的時間去學習,就能用它輕鬆構建跨語言跨平臺的分佈式應用系統了。

Hprose 支持衆多流行的編程語言,例如:

  • AAuto Quicker

  • ActionScript

  • ASP

  • C++

  • Delphi/Free Pascal

  • dotNET(C#, Visual Basic…)

  • Golang

  • Java

  • JavaScript

  • Node.js

  • Objective-C

  • Perl

  • PHP

  • Python

  • Ruby

通過 Hprose,你就可以在這些語言之間方便高效的實現互通了。

基礎實現

在同一個文件夾下,執行一下操作,分別是拉取組建的命令,創建兩個文件和執行 php 文件。

拉取 hprose 組件

composer require hprose/hprose

建立 server.php

<?php
require_once "./vendor/autoload.php";
use Hprose\Socket\Server;
function hello($name) {
return "Hello $name!";
}
$server = new Server("tcp://0.0.0.0:1314");
$server->setErrorTypes(E_ALL);
$server->setDebugEnabled();
$server->addFunction('hello');
$server->start();

建立 client.php

<?php
require_once "./vendor/autoload.php";
use \Hprose\Future;
use \Hprose\Socket\Client;
$test = new Client("tcp://127.0.0.1:1314");
$test->fullDuplex = true;
Future\co(function() use ($test) {
try {
var_dump((yield $test->hello("yield world1")));
var_dump((yield $test->hello("yield world2")));
var_dump((yield $test->hello("yield world3")));
var_dump((yield $test->hello("yield world4")));
var_dump((yield $test->hello("yield world5")));
var_dump((yield $test->hello("yield world6")));
}
catch (\Exception $e) {
echo ($e);
}
});

執行

php server.php
php client.php

結果

string(19) "Hello yield world1!"
string(19) "Hello yield world2!"
string(19) "Hello yield world3!"
string(19) "Hello yield world4!"
string(19) "Hello yield world5!"
string(19) "Hello yield world6!"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章