系统间通信3:RPC的基本概念
本文引用 : https://yinwj.blog.csdn.net/article/details/49453303
1. 概述
經過了詳細的信息格式、網絡IO模型的講解,并且通過JAVA RMI的講解進行了預熱。從這篇文章開始我們將進入這個系列博文的另一個重點知識體系的講解:RPC。在后續(xù)的幾篇文章中,我們首先講解RPC的基本概念,一個具體的RPC實現(xiàn)會有哪些基本要素構成,然后我們詳細介紹一款典型的RPC框架:Apache Thrift。
2. PRC概述
2.1 什么是RPC
RPC(Remote Procedure Call Protocol)遠程過程調用協(xié)議。一個通俗的描述是:客戶端在不知道調用細節(jié)的情況下,調用存在于遠程計算機上的某個對象,就像調用本地應用程序中的對象一樣。比較正式的描述是:一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協(xié)議。那么我們至少從這樣的描述中挖掘出幾個要點:
- RPC是協(xié)議:既然是協(xié)議就只是一套規(guī)范,那么就需要有人遵循這套規(guī)范來進行實現(xiàn)。目前典型的RPC實現(xiàn)包括:Dubbo、Thrift、GRPC、Hetty等。這里要說明一下,目前技術的發(fā)展趨勢來看,實現(xiàn)了RPC協(xié)議的應用工具往往都會附加其他重要功能,例如Dubbo還包括了服務管理、訪問權限管理等功能。
- 網絡協(xié)議和網絡IO模型對其透明:既然RPC的客戶端認為自己是在調用本地對象。那么傳輸層使用的是TCP/UDP還是HTTP協(xié)議,又或者是一些其他的網絡協(xié)議它就不需要關心了。既然網絡協(xié)議對其透明,那么調用過程中,使用的是哪一種網絡IO模型調用者也不需要關心。
- 信息格式對其透明:我們知道在本地應用程序中,對于某個對象的調用需要傳遞一些參數,并且會返回一個調用結果。至于被調用的對象內部是如何使用這些參數,并計算出處理結果的,調用方是不需要關心的。那么對于遠程調用來說,這些參數會以某種信息格式傳遞給網絡上的另外一臺計算機,這個信息格式是怎樣構成的,調用方是不需要關心的。
- 應該有跨語言能力:為什么這樣說呢?因為調用方實際上也不清楚遠程服務器的應用程序是使用什么語言運行的。那么對于調用方來說,無論服務器方使用的是什么語言,本次調用都應該成功,并且返回值也應該按照調用方程序語言所能理解的形式進行描述。
那么上面的描述情況可以用下圖表示:
2.2 RPC要素
當然,上圖是作為RPC的調用者所觀察到的現(xiàn)象(而實際情況是客戶端或多或少的還是需要知道一些調用RPC的細節(jié))。但是我們是要講解RPC的基本概念,所以RPC協(xié)議內部是怎么回事就要說清楚:
- Client:RPC協(xié)議的調用方。就像上文所描述的那樣,最理想的情況是RPC Client在完全不知道有RPC框架存在的情況下發(fā)起對遠程服務的調用。但實際情況來說Client或多或少的都需要指定RPC框架的一些細節(jié)。
- Server:在RPC規(guī)范中,這個Server并不是提供RPC服務器IP、端口監(jiān)聽的模塊。而是遠程服務方法的具體實現(xiàn)(在JAVA中就是RPC服務接口的具體實現(xiàn))。其中的代碼是最普通的和業(yè)務相關的代碼,甚至其接口實現(xiàn)類本身都不知道將被某一個RPC遠程客戶端調用。
- Stub/Proxy:RPC代理存在于客戶端,因為要實現(xiàn)客戶端對RPC框架“透明”調用,那么客戶端不可能自行去管理消息格式、不可能自己去管理網絡傳輸協(xié)議,也不可能自己去判斷調用過程是否有異常。這一切工作在客戶端都是交給RPC框架中的“代理”層來處理的。
- Message Protocol:在上文我們已經說到,一次完整的client-server的交互肯定是攜帶某種兩端都能識別的,共同約定的消息格式。RPC的消息管理層專門對網絡傳輸所承載的消息信息進行編號和解碼操作。**目前流行的技術趨勢是不同的RPC實現(xiàn),為了加強自身框架的效率都有一套(或者幾套)私有的消息格式。**例如前文所講到的RMI框架使用的消息協(xié)議為JRMP;后文我們將詳細講解的RPC框架Thrift也有私有的消息協(xié)議,“- Transfer/Network Protocol”(當然它還支持一些通用的消息格式,如JSON)。
- Transfer/Network Protocol:傳輸協(xié)議層負責管理RPC框架所使用的網絡協(xié)議、網絡IO模型。例如Hessian的傳輸協(xié)議基于HTTP(應用層協(xié)議);而Thrift的傳輸協(xié)議基于TCP(傳輸層協(xié)議)。傳輸層還需要統(tǒng)一RPC客戶端和RPC服務端所使用的IO模型;
- Selector/Processor:存在于RPC服務端,由于服務器端某一個RPC接口的實現(xiàn)的特性(它并不知道自己是一個將要被RPC提供給第三方系統(tǒng)調用的服務)。所以在RPC框架中應該有一種“負責執(zhí)行RPC接口實現(xiàn)”的角色。它負責了包括:管理RPC接口的注冊、判斷客戶端的請求權限、控制接口實現(xiàn)類的執(zhí)行在內的各種工作。
- IDL:實際上IDL(接口定義語言)并不是RPC實現(xiàn)中所必須的。但是需要跨語言的RPC框架一定會有IDL部分的存在。這是因為要找到一個各種語言能夠理解的消息結構、接口定義的描述形式。如果您的RPC實現(xiàn)沒有考慮跨語言性,那么IDL部分就不需要包括,例如JAVA RMI因為就是為了在JAVA語言間進行使用,所以JAVA RMI就沒有相應的IDL。
一定要說明一點,不同的RPC框架實現(xiàn)都有一定設計差異。例如生成Stub的方式不一樣,IDL描述語言不一樣、服務注冊的管理方式不一樣、運行服務實現(xiàn)的方式不一樣、采用的消息格式封裝不一樣、采用的網絡協(xié)議不一樣。但是基本的思路都是一樣的,上圖中的所列出的要素也都是具有的。
2.3 典型的RPC框架介紹
- JAVA RMI:是不是覺得前文中我們介紹RMI所提到幾個關鍵概念在RPC中都找得到一些影子。是的,RPC最早就是由SUN提出,并在后來由IETF ONC修訂。RMI就是一個典型的RPC實現(xiàn),只不過RMI不支持跨語言性,所以RMI中也沒有IDL存在的必要。但是RMI真心快,并且由于沒有IDL的存在,在構建一套完整的RPC實現(xiàn)時要比其他RPC框架少了一些步驟,所以使用起來也比較簡單。如果您的業(yè)務需求中并不存在跨語言的考慮,并且基本上主要系統(tǒng)都是用JAVA實現(xiàn),那么RMI絕對是您一個可以考慮的方案。
- GRPC:GRPC是一個高性能、通用的開源RPC框架,由Google主要面向移動應用開發(fā)并基于HTTP/2協(xié)議(注意是HTTP/2協(xié)議,不是我們常使用的HTTP 1_1。HTTP/2協(xié)議詳細的介紹可以參見官方地址:https://http2.github.io/)標準而設計,基于ProtoBuf(Protocol Buffers)序列化協(xié)議開發(fā),且支持眾多開發(fā)語言。為了支持GRPC的跨語言性,GRPC有一套獨立存在IDL語言。不過由于GRPC是Google的開源產品,在信息格式封裝方面Google主要還是推廣的自己的ProtoBuf,所以GPRC是不支持其他信息格式的(至少ProtoBuf效率是大家有目共睹的)。關于GRPC詳細的使用介紹,可以參見官方地址:https://github.com/grpc/grpc
- Thrift:Thrift是Facebook的一個開源項目,后來進入Apache進行孵化。Thrift也是支持跨語言的,所以它有自己的一套IDL。目前它支持幾乎所有主流的編程語言:C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages。Thrift可以支持多種信息格式,除了Thrift私有的二進制編碼規(guī)則和一種LVQ(類似于TLV消息格式)的消息格式,還有常規(guī)的JSON格式。Thrift的網絡協(xié)議建立在TCP協(xié)議基礎上,并且支持阻塞式IO模型和多路IO復用模型。我們將在后文詳細講解Apache Thrift的使用。Thrift也是目前最流行的RPC框架之一,從網絡上各種性能測試情況開,Thrift的性能都是領先的。Thrift的官網地址為:http://thrift.apache.org/
- Hetty:Hetty是一款構建于Netty和Hessian基礎上的高性能的RPC框架。Hetty的網絡協(xié)議基于HTTP,由于采用了Netty,所以Hetty支持阻塞式IO模型和多路IO復用模型。Hetty的消息格式采用私有的二進制流格式。
- 其他的RPC框架:除了上訴的RPC協(xié)議的實現(xiàn)外,還有:Wildfly、Hprose等等。Hprose是一款國人主導的RPC實現(xiàn),感興趣的讀者可以去看看(http://www.hprose.com/)。另外基于RPC的定義,Xfire,CXF這些Web Service框架也屬于RPC:WSDL描述文件就是他們的IDL,通過WSDL為不同的編程語言生成Stub、通過不同的Web服務器管理具體服務實現(xiàn)的運行過程、HTTP是它們的通信協(xié)議、XML是它們的消息格式。
3. RPC框架的性能依據
在物理服務器性能相同的情況下,以下幾個因素會對一款RPC框架的性能產生直接影響:
- 所支持的網絡IO模型:您的RPC服務器可以只支持傳統(tǒng)的阻塞式同步IO,也可以做一些改進讓您的RPC服務器支持非阻塞式同步IO,或者在您的服務器上實現(xiàn)對多路IO模型的支持。這樣的RPC服務器的性能在高并發(fā)狀態(tài)下,會有很大的差別。特別是單位處理性能下對內存、CPU資源的使用率。
- 基于的網絡協(xié)議:一般來說您可以選擇讓您的RPC使用應用層協(xié)議,例如HTTP或者之前我們提到的HTTP/2協(xié)議,或者使用TCP協(xié)議,讓您的RPC框架工作在傳輸層。工作在哪一層網絡上會對RPC框架的工作性能產生一定的影響,但是對RPC最終的性能影響并不大。但是至少從各種主流的RPC實現(xiàn)來看,沒有采用UDP協(xié)議做為主要的傳輸協(xié)議的。
- 選擇的消息封裝格式:選擇或者定義一種消息格式的封裝,要考慮的問題包括:消息的易讀性、描述單位內容時的消息體大小、編碼難度、解碼難度、解決半包/粘包問題的難易度。當然如果您只是想定義一種RPC專用的消息格式,那么消息的易讀性可能不是最需要考慮的。消息封裝格式的設計是目前各種RPC框架性能差異的最重要原因,這就是為什么幾乎所有主流的RPC框架都會設計私有的消息封裝格式的原因。
- 實現(xiàn)的服務處理管理方式:在高并發(fā)請求下,如何管理注冊的服務也是一個性能影響點。您可以讓RPC的Selector/Processor使用單個線程運行服務的具體實現(xiàn)(這意味著上一個客戶端的請求沒有處理完,下一個客戶端的請求就需要等待)、您也可以為每一個RPC具體服務的實現(xiàn)開啟一個獨立的線程運行(可以一次處理多個請求,但是操作系統(tǒng)對于“可運行的最大線程數”是有限制的)、您也可以線程池來運行RPC具體的服務實現(xiàn)(目前看來,在單個服務節(jié)點的情況下,這種方式是比較好的)、您還可以通過注冊代理的方式讓多個服務節(jié)點來運行具體的RPC服務實現(xiàn)。
總結
以上是生活随笔為你收集整理的系统间通信3:RPC的基本概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 系统间通信2:通信管理与远程方法调用RM
- 下一篇: 个人觉的不错的文章[来自CSDN]