RPC(Remote Procedure Call):遠程過程調用,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的思想.RPC 是一種技術思想而非一種規範或協議,常見 RPC 技術和框架有:web
目前流行的開源 RPC 框架仍是比較多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。編程
Thrift:是 Facebook 的開源 RPC 框架,主要是一個跨語言的服務開發框架。
用戶只要在其之上進行二次開發就行,應用對於底層的 RPC 通信等都是透明的。不過這個對於用戶來講須要學習特定領域語言這個特性,仍是有必定成本的。json
在一個典型 RPC 的使用場景中,包含了服務發現、負載、容錯、網絡傳輸、序列化等組件,其中「RPC 協議」就指明瞭程序如何進行網絡傳輸和序列化瀏覽器
RPC 的核心功能是指實現一個 RPC 最重要的功能模塊,就是上圖中的」RPC 協議」部分:安全
下面分別介紹核心 RPC 框架的重要組成:服務器
一次 RPC 調用流程以下:restful
接口調用一般包含兩個部分,序列化和通訊協議。常見的序列化協議包括json、xml、hession、protobuf、thrift、text、bytes等;通訊比較流行的是http、soap、websockect,RPC一般基於TCP實現。那麼restful使用的序列化協議一般是json,通訊協議是http;rpc是一種通訊協議,所以若是序列化使用json的話,那麼就是json-rpc網絡
RPC 的核心功能主要由 5 個模塊組成,若是想要本身實現一個 RPC,最簡單的方式要實現三個技術點,分別是:架構
服務尋址可使用 Call ID 映射。在本地調用中,函數體是直接經過函數指針來指定的,可是在遠程調用中,函數指針是不行的,由於兩個進程的地址空間是徹底不同的。併發
因此在 RPC 中,全部的函數都必須有本身的一個 ID。這個 ID 在全部進程中都是惟一肯定的。
客戶端在作遠程過程調用時,必須附上這個 ID。而後咱們還須要在客戶端和服務端分別維護一個函數和Call ID的對應表。
當客戶端須要進行遠程調用時,它就查一下這個表,找出相應的 Call ID,而後把它傳給服務端,服務端也經過查表,來肯定客戶端須要調用的函數,而後執行相應函數的代碼。
實現方式:服務註冊中心。
Registry(服務發現):藉助 JNDI 發佈並調用了 RMI 服務。實際上,JNDI 就是一個註冊表,服務端將服務對象放入到註冊表中,客戶端從註冊表中獲取服務對象。
RMI 服務在服務端實現以後須要註冊到 RMI Server 上,而後客戶端從指定的 RMI 地址上 Lookup 服務,調用該服務對應的方法便可完成遠程方法調用。
Registry 是個很重要的功能,當服務端開發完服務以後,要對外暴露,若是沒有服務註冊,則客戶端是無從調用的,即便服務端的服務就在那裏
客戶端怎麼把參數值傳給遠程的函數呢?在本地調用中,咱們只須要把參數壓到棧裏,而後讓函數本身去棧裏讀就行。
可是在遠程過程調用時,客戶端跟服務端是不一樣的進程,不能經過內存來傳遞參數。
這時候就須要客戶端把參數先轉成一個字節流,傳給服務端後,再把字節流轉成本身能讀取的格式。
只有二進制數據才能在網絡中傳輸,序列化和反序列化的定義是:
這個過程叫序列化和反序列化。同理,從服務端返回的值也須要序列化反序列化的過程。
網絡傳輸:遠程調用每每用在網絡上,客戶端和服務端是經過網絡鏈接的。
全部的數據都須要經過網絡傳輸,所以就須要有一個網絡傳輸層。網絡傳輸層須要把 Call ID 和序列化後的參數字節流傳給服務端,而後再把序列化後的調用結果傳回客戶端。
只要能完成這二者的,均可以做爲傳輸層使用。所以,它所使用的協議實際上是不限的,能完成傳輸就行。
儘管大部分 RPC 框架都使用 TCP 協議,但其實 UDP 也能夠,而 gRPC 乾脆就用了 HTTP2。
TCP 的鏈接是最多見的,簡要分析基於 TCP 的鏈接:一般 TCP 鏈接能夠是按需鏈接(須要調用的時候就先創建鏈接,調用結束後就立馬斷掉),也能夠是長鏈接(客戶端和服務器創建起鏈接以後保持長期持有,無論此時有無數據包的發送,能夠配合心跳檢測機制按期檢測創建的鏈接是否存活有效),多個遠程過程調用共享同一個鏈接。
因此,要實現一個 RPC 框架,只須要把如下三點實現了就基本完成了:
在 RPC 中可選的網絡傳輸方式有多種,能夠選擇 TCP 協議、UDP 協議、HTTP 協議。
由服務的調用方與服務的提供方創建 Socket 鏈接,並由服務的調用方經過 Socket 將須要調用的接口名稱、方法名稱和參數序列化後傳遞給服務的提供方,服務的提供方反序列化後再利用反射調用相關的方法。
將結果返回給服務的調用方,整個基於 TCP 協議的 RPC 調用大體如此。
可是在實例應用中則會進行一系列的封裝,如 RMI 即是在 TCP 協議上傳遞可序列化的 Java 對象。
該方法更像是訪問網頁同樣,只是它的返回結果更加單一簡單。
其大體流程爲:由服務的調用者向服務的提供者發送請求,這種請求的方式多是 GET、POST、PUT、DELETE 等中的一種,服務的提供者可能會根據不一樣的請求方式作出不一樣的處理,或者某個方法只容許某種請求方式。
而調用的具體方法則是根據 URL 進行方法調用,而方法所須要的參數多是對服務調用方傳輸過去的 XML 數據或者 JSON 數據解析後的結果,返回 JOSN 或者 XML 的數據結果。
因爲目前有不少開源的 Web 服務器,如 Tomcat,因此其實現起來更加容易,就像作 Web 項目同樣
基於 TCP 的協議實現的 RPC 調用,因爲 TCP 協議處於協議棧的下層,可以更加靈活地對協議字段進行定製,減小網絡開銷,提升性能,實現更大的吞吐量和併發數。
可是須要更多關注底層複雜的細節,實現的代價更高。同時對不一樣平臺,如安卓,iOS 等,須要從新開發出不一樣的工具包來進行請求發送和相應解析,工做量大,難以快速響應和知足用戶需求。
基於 HTTP 協議實現的 RPC 則可使用 JSON 和 XML 格式的請求或響應數據。
而 JSON 和 XML 做爲通用的格式標準(使用 HTTP 協議也須要序列化和反序列化,不過這不是該協議下關心的內容,成熟的 Web 程序已經作好了序列化內容),開源的解析工具已經至關成熟,在其上進行二次開發會很是便捷和簡單。
可是因爲 HTTP 協議是上層協議,發送包含同等內容的信息,使用 HTTP 協議傳輸所佔用的字節數會比使用 TCP 協議傳輸所佔用的字節數更高。
所以在同等網絡下,經過 HTTP 協議傳輸相同內容,效率會比基於 TCP 協議的數據效率要低,信息傳輸所佔用的時間也會更長,固然壓縮數據,可以縮小這一差距。
在 OpenStack 中服務與服務之間使用 RESTful API 調用,而在服務內部則使用 RPC 調用各個功能模塊。
正是因爲使用了 RPC 來解耦服務內部功能模塊,使得 OpenStack 的服務擁有擴展性強,耦合性低等優勢。
OpenStack 的 RPC 架構中,加入了消息隊列 RabbitMQ,這樣作的目的是爲了保證 RPC 在消息傳遞過程當中的安全性和穩定性。
下面分析 OpenStack 中使用 RabbitMQ 如何實現 RPC 的調用。
使用 RabbitMQ 的好處:
RPC 主要用於公司內部的服務調用,性能消耗低,傳輸效率高,實現複雜
RESTful API 主要用於對外的異構環境,瀏覽器接口調用,App 接口調用,第三方接口調用等
RPC 使用場景(大型的網站,內部子系統較多、接口很是多的狀況下適合使用 RPC):