本文轉自developer.51cto.com/art/201906/…html
RPC(Remote Procedure Call):遠程過程調用,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的思想。python
RPC 是一種技術思想而非一種規範或協議,常見 RPC 技術和框架有:git
目前流行的開源 RPC 框架仍是比較多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。程序員
在一個典型 RPC 的使用場景中,包含了服務發現、負載、容錯、網絡傳輸、序列化等組件,其中「RPC 協議」就指明瞭程序如何進行網絡傳輸和序列化。github
圖 1:完整 RPC 架構圖面試
以下是 Dubbo 的設計架構圖,分層清晰,功能複雜:編程
圖 2:Dubbo 架構圖json
RPC 核心功能小程序
RPC 的核心功能是指實現一個 RPC 最重要的功能模塊,就是上圖中的」RPC 協議」部分:api
圖 3:RPC 核心功能
一個 RPC 的核心功能主要有 5 個部分組成,分別是:客戶端、客戶端 Stub、網絡傳輸模塊、服務端 Stub、服務端等。
圖 4:RPC 核心功能圖
下面分別介紹核心 RPC 框架的重要組成:
Server.py:
fromSimpleXMLRPCServer importSimpleXMLRPCServer
deffun_add(a,b):
totle = a + b
returntotle
if__name__ == '__main__':
s = SimpleXMLRPCServer(( '0.0.0.0', 8080)) #開啓xmlrpcserver
s.register_function(fun_add) #註冊函數fun_add
print"server is online..."
s.serve_forever #開啓循環等待複製代碼
Client.py:
fromxmlrpclib importServerProxy #導入xmlrpclib的包
s = ServerProxy( "http://172.171.5.205:8080") #定義xmlrpc客戶端
prints.fun_add( 2, 3) #調用服務器端的函數複製代碼
開啓服務端:
開啓客戶端:
Wireshark 抓包分析過程
客戶端去往服務端:
通訊使用 HTTP 協議,XML 文件傳輸格式。傳輸的字段包括:方法名 methodName,兩個參數 2,3。
圖 5:Request 抓包
服務端返回結果,字段返回值 Value,結果是 5:
圖 6:Response 抓包
在這兩次網絡傳輸中使用了 HTTP 協議,創建 HTTP 協議之間有 TCP 三次握手,斷開 HTTP 協議時有 TCP 四次揮手。
圖 7:基於 HTTP 協議的 RPC 鏈接過程
詳細調用過程
Python 自帶 RPC 的 Demo 小程序的實現過程,流程和分工角色能夠用下圖來表示:
圖 8:RPC 調用詳細流程圖
一次 RPC 調用流程以下:
RPC 的核心功能主要由 5 個模塊組成,若是想要本身實現一個 RPC,最簡單的方式要實現三個技術點,分別是:
服務尋址可使用 Call ID 映射。在本地調用中,函數體是直接經過函數指針來指定的,可是在遠程調用中,函數指針是不行的,由於兩個進程的地址空間是徹底不同的。
因此在 RPC 中,全部的函數都必須有本身的一個 ID。這個 ID 在全部進程中都是惟一肯定的。
客戶端在作遠程過程調用時,必須附上這個 ID。而後咱們還須要在客戶端和服務端分別維護一個函數和Call ID的對應表。
當客戶端須要進行遠程調用時,它就查一下這個表,找出相應的 Call ID,而後把它傳給服務端,服務端也經過查表,來肯定客戶端須要調用的函數,而後執行相應函數的代碼。
實現方式 服務註冊中心。
要調用服務,首先你須要一個服務註冊中心去查詢對方服務都有哪些實例。Dubbo 的服務註冊中心是能夠配置的,官方推薦使用 Zookeeper。
實現案例: RMI(Remote Method Invocation,遠程方法調用)也就是 RPC 自己的實現方式。
圖 9:RMI 架構圖
Registry(服務發現): 藉助 JNDI 發佈並調用了 RMI服務。實際上,JNDI 就是一個註冊表,服務端將服務對象放入到註冊表中,客戶端從註冊表中獲取服務對象。
RMI 服務在服務端實現以後須要註冊到 RMI Server 上,而後客戶端從指定的 RMI 地址上 Lookup 服務,調用該服務對應的方法便可完成遠程方法調用。
Registry 是個很重要的功能,當服務端開發完服務以後,要對外暴露,若是沒有服務註冊,則客戶端是無從調用的,即便服務端的服務就在那裏。
客戶端怎麼把參數值傳給遠程的函數呢?在本地調用中,咱們只須要把參數壓到棧裏,而後讓函數本身去棧裏讀就行。
可是在遠程過程調用時,客戶端跟服務端是不一樣的進程,不能經過內存來傳遞參數。
這時候就須要客戶端把參數先轉成一個字節流,傳給服務端後,再把字節流轉成本身能讀取的格式。
這個過程叫序列化和反序列化。同理,從服務端返回的值也須要序列化反序列化的過程。
優勢 1 簡單易用開發成本低 2 跨語言 3 輕量級數據交換 4 非冗長性(對比xml標籤簡單括號閉環)
缺點 1 體積大,影響高併發 2 無版本檢查,本身作兼容 3 片斷的建立和驗證過程比通常的XML複雜 4 缺少命名空間致使信息混合
總結:最簡單最通用的應用協議,使用普遍,開發效率高,性能相對較低,維護成本較高。
Protobuf是一種以有效並可擴展的格式編碼結構化數據的方式。
優勢 1 跨語言,可自定義數據結構。 2 字段被編號,新添加的字段不影響老結構。解決了向後兼容問題。 3 自動化生成代碼,簡單易用。 4 二進制消息,效率高,性能高。 5 Netty等框架集成了該協議,提供了編×××提升開發效率。
缺點 1 二進制格式,可讀性差(抓包dump後的數據很難看懂) 2 對象冗餘,字段不少,生成的類較大,佔用空間。 3 默認不具有動態特性(能夠經過動態定義生成消息類型或者動態編譯支持)
總結:簡單快速上手,高效兼容性強,維護成本較高。
優勢 1 序列化和RPC支持一站式解決,比pb更方便 2 跨語言,IDL接口定義語言,自動生成多語言文件 3 省流量,體積較小 4 包含完整的客戶端/服務端堆棧,可快速實現RPC 5 爲服務端提供了多種工做模式,如線程池模型、非阻塞模型
缺點 1 早期版本問題較大,0.7之前有兼容性問題 2 不支持雙通道 3 rpc方法非線程安全,服務器容易被掛死,須要串行化。 4 默認不具有動態特性(能夠經過動態定義生成消息類型或者動態編譯支持) 5 開發環境、編譯較麻煩
總結:跨語言、實現簡單,初次使用較麻煩,須要避免使用問題和場景限制。
網絡傳輸: 遠程調用每每用在網絡上,客戶端和服務端是經過網絡鏈接的。
全部的數據都須要經過網絡傳輸,所以就須要有一個網絡傳輸層。網絡傳輸層須要把 Call ID 和序列化後的參數字節流傳給服務端,而後再把序列化後的調用結果傳回客戶端。
只要能完成這二者的,均可以做爲傳輸層使用。所以,它所使用的協議實際上是不限的,能完成傳輸就行。
儘管大部分 RPC 框架都使用 TCP 協議,但其實 UDP 也能夠,而 gRPC 乾脆就用了 HTTP2。
TCP 的鏈接是最多見的,簡要分析基於 TCP 的鏈接:
一般 TCP 鏈接能夠是按需鏈接(須要調用的時候就先創建鏈接,調用結束後就立馬斷掉),也能夠是長鏈接(客戶端和服務器創建起鏈接以後保持長期持有,無論此時有無數據包的發送,能夠配合心跳檢測機制按期檢測創建的鏈接是否存活有效),多個遠程過程調用共享同一個鏈接。
因此,要實現一個 RPC 框架,只須要把如下三點實現了就基本完成了:
RPC 核心之網絡傳輸協議
在第三節中說明了要實現一個 RPC,須要選擇網絡傳輸的方式。
圖 10:網絡傳輸
在 RPC 中可選的網絡傳輸方式有多種,能夠選擇 TCP 協議、UDP 協議、HTTP 協議。
每一種協議對總體的性能和效率都有不一樣的影響,如何選擇一個正確的網絡傳輸協議呢?首先要搞明白各類傳輸協議在 RPC 中的工做方式。
由服務的調用方與服務的提供方創建 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: 假設你是一個飯店裏的服務員,顧客向你點菜,可是你不會作菜,因此你採集了顧客要點什麼以後告訴後廚去作顧客點的菜,這叫 RPC(remote procedure call),由於廚房的廚師相對於服務員而言是另一我的(在計算機的世界裏就是 Remote 的機器上的一個進程)。廚師作好了的菜就是RPC的返回值。
任務隊列和消息隊列: 本質都是隊列,因此就只舉一個任務隊列的例子。假設這個飯店在高峯期顧客不少,而廚師只有不多的幾個,因此服務員們不得不把單子按下單順序放在廚房的桌子上,供廚師們一個一個作,這一堆單子就是任務隊列,廚師們每作完一個菜,就從桌子上的訂單裏再取出一個單子繼續作菜。
角色分擔以下圖:
圖 11:RabbitMQ 在 RPC 中角色
使用 RabbitMQ 的好處:
RabbitMQ 的三種類型的交換器
RabbitMQ 使用 Exchange(交換機)和 Queue(隊列)來實現消息隊列。
在 RabbitMQ 中一共有三種交換機類型,每一種交換機類型都有很鮮明的特徵。
基於這三種交換機類型,OpenStack 完成兩種 RPC 的調用方式。首先簡單介紹三種交換機。
圖 12:RabbitMQ 架構圖
①廣播式交換器類型(Fanout)
該類交換器不分析所接收到消息中的 Routing Key,默認將消息轉發到全部與該交換器綁定的隊列中去。
圖 13:廣播式交換機
②直接式交換器類型(Direct)
該類交換器須要精確匹配 Routing Key 與 Binding Key,如消息的 Routing Key = Cloud,那麼該條消息只能被轉發至 Binding Key = Cloud 的消息隊列中去。
圖 14:直接式交換機
③主題式交換器(Topic Exchange)
該類交換器經過消息的 Routing Key 與 Binding Key 的模式匹配,將消息轉發至全部符合綁定規則的隊列中。
Binding Key 支持通配符,其中「*」匹配一個詞組,「#」匹配多個詞組(包括零個)。
圖 15:主題式交換機
注:以上四張圖片來自博客園,若有侵權,請聯繫做者:www.cnblogs.com/dwlsxj/p/Ra…
當生產者發送消息 Routing Key=F.C.E 的時候,這時候只知足 Queue1,因此會被路由到 Queue 中。
若是 Routing Key=A.C.E 這時候會被同時路由到 Queue1 和 Queue2 中,若是 Routing Key=A.F.B 時,這裏只會發送一條消息到 Queue2 中。
Nova 基於 RabbitMQ 實現兩種 RPC 調用:
其中 RPC.CALL 基於請求與響應方式,RPC.CAST 只是提供單向請求,兩種 RPC 調用方式在 Nova 中均有典型的應用場景。
RPC.CALL
RPC.CALL 是一種雙向通訊流程,即 RabbitMQ 接收消息生產者生成的系統請求消息,消息消費者通過處理以後將系統相應結果反饋給調用程序。
圖 16:RPC.CALL 原理圖
一個用戶經過 Dashboard 建立一個虛擬機,界面通過消息封裝後發送給 NOVA-API。
NOVA-API 做爲消息生產者,將該消息以 RPC.CALL 方式經過 Topic 交換器轉發至消息隊列。
此時,Nova-Compute 做爲消息消費者,接收該信息並經過底層虛擬化軟件執行相應虛擬機的啓動進程。
待用戶虛擬機成功啓動以後,Nova-Compute 做爲消息生產者經過 Direct 交換器和響應的消息隊列將虛擬機啓動成功響應消息反饋給 Nova-API。
此時 Nova-API 做爲消息消費者接收該消息並通知用戶虛擬機啓動成功。
RPC.CALL 工做原理以下圖:
圖 17:RPC.CALL 具體實現圖
工做流程:
若是有多個線程同時進行遠程方法調用,這時創建在 Client Server 之間的 Socket 鏈接上會有不少雙方發送的消息傳遞,先後順序也多是隨機的。
Server 處理完結果後,將結果消息發送給 Client,Client 收到不少消息,怎麼知道哪一個消息結果是原先哪一個線程調用的?
Client 線程每次經過 Socket 調用一次遠程接口前,生成一個惟一的 ID,即 Request ID(Request ID必需保證在一個 Socket 鏈接裏面是惟一的),通常經常使用 AtomicLong 從 0 開始累計數字生成惟一 ID。
RPC.CAST
RPC.CAST 的遠程調用流程與 RPC.CALL 相似,只是缺乏了系統消息響應流程。
一個 Topic 消息生產者發送系統請求消息到 Topic 交換器,Topic 交換器根據消息的 Routing Key 將消息轉發至共享消息隊列。
與共享消息隊列相連的全部 Topic 消費者接收該系統請求消息,並把它傳遞給響應的服務端進行處理。
其調用流程如圖所示:
圖 18:RPC.CAST 原理圖
鏈接設計
RabbitMQ 實現的 RPC 對網絡的通常設計思路:消費者是長鏈接,發送者是短鏈接。但能夠自由控制長鏈接和短鏈接。
通常消費者是長鏈接,隨時準備接收處理消息;並且涉及到 RabbitMQ Queues、Exchange 的 auto-deleted 等沒特殊需求不必作短鏈接。發送者可使用短鏈接,不會長期佔住端口號,節省端口資源。
Nova 中 RPC 代碼設計:
簡單對比 RPC 和 Restful API
REST 最大的幾個特色爲:資源、統一接口、URI 和無狀態。
①資源
所謂"資源",就是網絡上的一個實體,或者說是網絡上的一個具體信息。它能夠是一段文本、一張圖片、一首歌曲、一種服務,就是一個具體的實在。
②統一接口
RESTful 架構風格規定,數據的元操做,即 CRUD(Create,Read,Update 和 Delete,即數據的增刪查改)操做,分別對應於 HTTP 方法:GET 用來獲取資源,POST 用來新建資源(也能夠用於更新資源),PUT 用來更新資源,DELETE 用來刪除資源,這樣就統一了數據操做的接口,僅經過 HTTP 方法,就能夠完成對數據的全部增刪查改工做。
③URL
能夠用一個 URI(統一資源定位符)指向資源,即每一個 URI 都對應一個特定的資源。
要獲取這個資源,訪問它的 URI 就能夠,所以 URI 就成了每個資源的地址或識別符。
④無狀態
所謂無狀態的,即全部的資源,均可以經過 URI 定位,並且這個定位與其餘資源無關,也不會由於其餘資源的變化而改變。有狀態和無狀態的區別,舉個簡單的例子說明一下。
如查詢員工的工資,若是查詢工資是須要登陸系統,進入查詢工資的頁面,執行相關操做後,獲取工資的多少,則這種狀況是有狀態的。
由於查詢工資的每一步操做都依賴於前一步操做,只要前置操做不成功,後續操做就沒法執行。
若是輸入一個 URI便可獲得指定員工的工資,則這種狀況是無狀態的,由於獲取工資不依賴於其餘資源或狀態。
且這種狀況下,員工工資是一個資源,由一個 URI與之對應,能夠經過 HTTP 中的 GET 方法獲得資源,這是典型的 RESTful 風格。
面對對象不一樣:
RESTful 是面向資源的設計架構,但在系統中有不少對象不能抽象成資源,好比登陸,修改密碼等而 RPC 能夠經過動做去操做資源。因此在操做的全面性上 RPC 大於 RESTful。
傳輸效率:
複雜度:
RPC 實現(參見第一節)須要實現編碼,序列化,網絡傳輸等。而 RESTful 不要關注這些,RESTful 實現更簡單。
靈活性:
RPC 主要用於公司內部的服務調用,性能消耗低,傳輸效率高,實現複雜。
HTTP 主要用於對外的異構環境,瀏覽器接口調用,App 接口調用,第三方接口調用等。
RPC 使用場景(大型的網站,內部子系統較多、接口很是多的狀況下適合使用 RPC):
developer.51cto.com/art/201906/…
Java技術倉庫《Java程序員複習指南》
整合全網優質Java學習內容,幫助你從基礎到進階系統化複習Java
全網最熱的Java面試指南,共200多頁,很是實用,無論是用於複習仍是準備面試都是不錯的。 在公衆號【Java技術江湖】回覆「PDF」便可免費領取。