當前位置:
首頁 > 知識 > Remote Procedure Call基本原理

Remote Procedure Call基本原理

近幾年隨著微服務化項目的崛起,逐漸成為許多公司中大型分散式系統架構的主流方式,而今天所說的 RPC 在這其中扮演著至關重要的角色。隨著這段日子公司項目微服務化的演進,發現在日常開發中都在隱式或顯式的使用 RPC,一些剛剛接觸 RPC 的小夥伴會感覺無所適從,而一些入行多年的老手雖然使用 RPC 經驗豐富,但有些對其原理也一知半解,缺乏對原理的深入理解,往往也會造成開發中的一些誤用。

什麼是RPC?

RPC(Remote Procedure Call)—遠程過程調用,它是一種通過網路從遠程計算機程序上請求服務,而不需要了解底層網路技術的協議。也就是說兩台伺服器A,B,一個應用部署在A伺服器上,想要調用B伺服器上應用提供的方法,由於不在一個內存空間,不能直接調用,需要通過網路來表達調用的語義和傳達調用的數據。

RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通信程序之間攜帶信息數據。在OSI網路通信模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網路分散式多程序在內的應用程序更加容易。現在業界有很多開源的優秀 RPC 框架,例如 Spring Cloud、Dubbo、Thrift 等。

RPC 起源

RPC 這個概念術語在上世紀 80 年代由 Bruce Jay Nelson 提出。這裡我們追溯下當初開發 RPC 的原動機是什麼?在 Nelson 的論文 「Implementing Remote Procedure Calls」 中他提到了幾點:

簡單:RPC 概念的語義十分清晰和簡單,這樣建立分散式計算就更容易。

高效:過程調用看起來十分簡單而且高效。

通用:在單機計算中過程往往是不同演算法部分間最重要的通信機制。

通俗一點說,就是一般程序員對於本地的過程調用很熟悉,那麼我們把 RPC 作成和本地調用完全類似,那麼就更容易被接受,使用起來毫無障礙。Nelson 的論文發表於 30 年前,其觀點今天看來確實高瞻遠矚,今天我們使用的 RPC 框架基本就是按這個目標來實現的。

RPC 結構

Nelson 的論文中指出實現 RPC 的程序包括 5 個部分:

User

User-stub

RPCRuntime

Server-stub

Server

這裡 user 就是 client 端,當 user 想發起一個遠程調用時,它實際是通過本地調用 user-stub。user-stub 負責將調用的介面、方法和參數通過約定的協議規範進行編碼並通過本地的 RPCRuntime 實例傳輸到遠端的實例。遠端 RPCRuntime 實例收到請求後交給 server-stub 進行解碼後發起本地端調用,調用結果再返回給 user 端。

以上是粗粒度的 RPC 實現概念結構,接下來我們進一步細化它應該由哪些組件構成,如下圖所示。

RPC 服務方通過 RpcServer 去導出(export)遠程介面方法,而客戶方通過 RpcClient 去引入(import)遠程介面方法。客戶方像調用本地方法一樣去調用遠程介面方法,RPC 框架提供介面的代理實現,實際的調用將委託給代理RpcProxy 。代理封裝調用信息並將調用轉交給RpcInvoker 去實際執行。在客戶端的RpcInvoker 通過連接器RpcConnector 去維持與服務端的通道RpcChannel,並使用RpcProtocol 執行協議編碼(encode)並將編碼後的請求消息通過通道發送給服務方。

RPC 服務端接收器 RpcAcceptor 接收客戶端的調用請求,同樣使用RpcProtocol? 執行協議解碼(decode)。解碼後的調用信息傳遞給RpcProcessor 去控制處理調用過程,最後再委託調用給RpcInvoker 去實際執行並返回調用結果。如下是各個部分的詳細職責:

1. RpcServer

負責導出(export)遠程介面

2. RpcClient

負責導入(import)遠程介面的代理實現

3. RpcProxy

遠程介面的代理實現

4. RpcInvoker

客戶方實現:負責編碼調用信息和發送調用請求到服務方並等待調用結果返回

服務方實現:負責調用服務端介面的具體實現並返回調用結果

5. RpcProtocol

負責協議編/解碼

6. RpcConnector

負責維持客戶方和服務方的連接通道和發送數據到服務方

7. RpcAcceptor

負責接收客戶方請求並返回請求結果

8. RpcProcessor

負責在服務方控制調用過程,包括管理調用線程池、超時時間等

9. RpcChannel

數據傳輸通道

RPC 工作原理

RPC的設計由Client,Client stub,Network ,Server stub,Server構成。 其中Client就是用來調用服務的,Cient stub是用來把調用的方法和參數序列化的(因為要在網路中傳輸,必須要把對象轉變成位元組),Network用來傳輸這些信息到Server stub, Server stub用來把這些信息反序列化的,Server就是服務的提供者,最終調用的就是Server提供的方法。

Client像調用本地服務似的調用遠程服務;

Client stub接收到調用後,將方法、參數序列化

客戶端通過sockets將消息發送到服務端

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

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

本地服務執行(對於服務端來說是本地執行)並將結果返回給Server stub

Server stub將返回結果打包成消息(將結果消息對象序列化)

服務端通過sockets將消息發送到客戶端

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

客戶端得到最終結果。

RPC 調用分以下兩種:

同步調用:客戶方等待調用執行完成並返回結果。

非同步調用:客戶方調用後不用等待執行結果返回,但依然可以通過回調通知等方式獲取返回結果。若客戶方不關心調用返回結果,則變成單向非同步調用,單向調用不用返回結果。

非同步和同步的區分在於是否等待服務端執行完成並返回結果。

RPC 能幹什麼?

RPC 的主要功能目標是讓構建分散式計算(應用)更容易,在提供強大的遠程調用能力時不損失本地調用的語義簡潔性。為實現該目標,RPC 框架需提供一種透明調用機制,讓使用者不必顯式的區分本地調用和遠程調用,在之前給出的一種實現結構,基於 stub 的結構來實現。下面我們將具體細化 stub 結構的實現。

可以做到分散式,現代化的微服務

部署靈活

解耦服務

擴展性強

RPC的目的是讓你在本地調用遠程的方法,而對你來說這個調用是透明的,你並不知道這個調用的方法是部署哪裡。通過RPC能解耦服務,這才是使用RPC的真正目的。

總結

這篇文章介紹了 RPC 的一些基本原理,相信到這裡您已經對 RPC 有了一定理解。其實發現實現一個 RPC 不算難,難的是實現一個高性能高可靠的RPC框架。比如,既然是分散式了,那麼一個服務可能有多個實例,你在調用時,要如何獲取這些實例的地址呢?這時候就需要一個服務註冊中心,比如在Dubbo中,就可以使用Zookeeper作為註冊中心,在調用時,從Zookeeper獲取服務的實例列表,再從中選擇一個進行調用。那麼選哪個調用好呢?這時候就需要負載均衡了,於是你又得考慮如何實現複雜均衡,比如Dubbo就提供了好幾種負載均衡策略。所以請繼續關注我的另外兩篇文章RPC與服務化的關係和註冊中心,配置中心, 服務發現淺談,相信會幫助對RPC設計和實現有更多的理解。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 千鋒JAVA開發學院 的精彩文章:

布局大殺器—ConstraintLayout
MySQL存儲引擎、MyISAM、InnoDB

TAG:千鋒JAVA開發學院 |