RPC架構-遠程過程調用


一、什么是RPC

  RPC(Remote Procedure Call):遠程過程調用,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的思想。

  RPC 是一種技術思想而非一種規范或協議,常見 RPC 技術和框架有:

  • 應用級的服務框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud。
  • 遠程通信協議:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。
  • 通信框架:MINA 和 Netty。

  目前流行的開源 RPC 框架還是比較多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。下面重點介紹三種:

  • gRPC:是 Google 公布的開源軟件,基於HTTP 2.0 協議,並支持常見的眾多編程語言。RPC 框架是基於 HTTP 協議實現的,底層使用到了 Netty 框架的支持。
  • Thrift:是 Facebook 的開源 RPC 框架,主要是一個跨語言的服務開發框架。用戶只要在其之上進行二次開發就行,應用對於底層的 RPC 通訊等都是透明的。不過這個對於用戶來說需要學習特定領域語言這個特性,還是有一定成本的。
  • Dubbo:是阿里集團開源的一個極為出名的 RPC 框架,在很多互聯網公司和企業應用中廣泛使用。協議和序列化框架都可以插拔是極其鮮明的特色。

二、框架結構

  在一個典型 RPC 的使用場景中,包含了服務發現、負載、容錯、網絡傳輸、序列化等組件,其中“RPC 協議”就指明了程序如何進行網絡傳輸和序列化。

 

三、關鍵技術

  RPC 的核心功能主要由 5 個模塊組成,如果想要自己實現一個 RPC,最簡單的方式要實現三個技術點,分別是:

  • 服務尋址
  • 數據流的序列化和反序列化
  • 網絡傳輸

3.1 服務尋址

  服務尋址可以使用 Call ID 映射。在本地調用中,函數體是直接通過函數指針來指定的,但是在遠程調用中,函數指針是不行的,因為兩個進程的地址空間是完全不一樣的。

  所以在 RPC 中,所有的函數都必須有自己的一個 ID。這個 ID 在所有進程中都是唯一確定的。

  客戶端在做遠程過程調用時,必須附上這個 ID。然后我們還需要在客戶端和服務端分別維護一個函數和Call ID的對應表。

  當客戶端需要進行遠程調用時,它就查一下這個表,找出相應的 Call ID,然后把它傳給服務端,服務端也通過查表,來確定客戶端需要調用的函數,然后執行相應函數的代碼。

  實現方式:服務注冊中心。

  要調用服務,首先你需要一個服務注冊中心去查詢對方服務都有哪些實例。Dubbo 的服務注冊中心是可以配置的,官方推薦使用 Zookeeper。

  實現案例:RMI(Remote Method Invocation,遠程方法調用)也就是 RPC 本身的實現方式。

  Registry(服務發現):借助 JNDI 發布並調用了 RMI 服務。實際上,JNDI 就是一個注冊表,服務端將服務對象放入到注冊表中,客戶端從注冊表中獲取服務對象。

  RMI 服務在服務端實現之后需要注冊到 RMI Server 上,然后客戶端從指定的 RMI 地址上 Lookup 服務,調用該服務對應的方法即可完成遠程方法調用。

  Registry 是個很重要的功能,當服務端開發完服務之后,要對外暴露,如果沒有服務注冊,則客戶端是無從調用的,即使服務端的服務就在那里。

3.2 序列化和反序列化

  客戶端怎么把參數值傳給遠程的函數呢?在本地調用中,我們只需要把參數壓到棧里,然后讓函數自己去棧里讀就行。

  但是在遠程過程調用時,客戶端跟服務端是不同的進程,不能通過內存來傳遞參數。

  這時候就需要客戶端把參數先轉成一個字節流,傳給服務端后,再把字節流轉成自己能讀取的格式。

  只有二進制數據才能在網絡中傳輸,序列化和反序列化的定義是:

  • 將對象轉換成二進制流的過程叫做序列化
  • 將二進制流轉換成對象的過程叫做反序列化

  這個過程叫序列化和反序列化。同理,從服務端返回的值也需要序列化反序列化的過程。

3.3 網絡傳輸

  網絡傳輸:遠程調用往往用在網絡上,客戶端和服務端是通過網絡連接的。

  所有的數據都需要通過網絡傳輸,因此就需要有一個網絡傳輸層。網絡傳輸層需要把 Call ID 和序列化后的參數字節流傳給服務端,然后再把序列化后的調用結果傳回客戶端。

  只要能完成這兩者的,都可以作為傳輸層使用。因此,它所使用的協議其實是不限的,能完成傳輸就行。

  盡管大部分 RPC 框架都使用 TCP 協議,但其實 UDP 也可以,而 gRPC 干脆就用了 HTTP2。

  TCP 的連接是最常見的,簡要分析基於 TCP 的連接:通常 TCP 連接可以是按需連接(需要調用的時候就先建立連接,調用結束后就立馬斷掉),也可以是長連接(客戶端和服務器建立起連接之后保持長期持有,不管此時有無數據包的發送,可以配合心跳檢測機制定期檢測建立的連接是否存活有效),多個遠程過程調用共享同一個連接。

  所以,要實現一個 RPC 框架,只需要把以下三點實現了就基本完成了:

  • Call ID 映射:可以直接使用函數字符串,也可以使用整數 ID。映射表一般就是一個哈希表。
  • 序列化反序列化:可以自己寫,也可以使用 Protobuf 或者 FlatBuffers 之類的。
  • 網絡傳輸庫:可以自己寫 Socket,或者用 Asio,ZeroMQ,Netty 之類。

四、使用場景

  RPC 主要用於公司內部的服務調用,性能消耗低,傳輸效率高,實現復雜。

  HTTP 主要用於對外的異構環境,瀏覽器接口調用,App 接口調用,第三方接口調用等。

  RPC 使用場景(大型的網站,內部子系統較多、接口非常多的情況下適合使用 RPC):

  • 長鏈接。不必每次通信都要像 HTTP 一樣去 3 次握手,減少了網絡開銷。
  • 注冊發布機制。RPC 框架一般都有注冊中心,有豐富的監控管理;發布、下線接口、動態擴展等,對調用方來說是無感知、統一化的操作。
  • 安全性,沒有暴露資源操作。
  • 微服務支持。就是最近流行的服務化架構、服務化治理,RPC 框架是一個強力的支撐。

五、結語

  之前寫的窗體應用和web項目等都是單機程序,使用的架構基本上算是MVC模式,從未了解過RPC。但是此次通過搜索閱讀RPC相關的文章博客等,我對RPC有了初步的了解。此外還在《分布式服務框架原理與實踐》(李林峰著)中知道了應用架構的演進歷史。

 

  • MVC (Modle View Controller) 架構: 當業務規模很小時,將所有功能都部署在同一個進程中,通過雙機或者前置負載均衡器實現負載分流;此時,用於分離前后台邏輯的 MVC 架構是關鍵。
  • RPC (Remote Procedure Call)架構:當垂直應用越來越多,應用之間交互不可避免,將核心和公共業務抽取出來,作為獨立的服務,實現前后台邏輯分離。此時,用於提高業務復用及拆分的 RPC 框架是關鍵。
  • SOA (Service Oriented Architecture)架構:隨着業務發展,服務數量越來越多,服務生命周期管控和運行態的治理成為瓶頸,此時用於提升服務質量的 SOA 服務治理是關鍵。
  • 微服務架構:隨着敏捷開發、持續支付、DevOps 理論的發展和實踐,以及基於 Docker 等輕量級容器 (LXC) 部署應用和服務的成熟,微服務架構開始流行,逐漸成為應用架構的未來演進方向。通過服務的原子化拆分,以及微服務的獨立打包、部署和升級,小團隊敏捷交付,應用的交付周期將縮短,運營成本也將大幅下降。

六、參考資料

  1.花了一個星期,我終於把RPC框架整明白了! - 51CTO.COM  https://developer.51cto.com/art/201906/597963.htm

  2.《分布式服務框架原理與實踐》(李林峰著)下載鏈接:https://www.jb51.net/books/506808.html#downintro2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM