本文主要講解 RPC 遠程服務調用相關的知識。
RPC 遠程服務調用是分布式服務架構的基礎,無論微服務設計上層如何發展,討論服務治理都繞不開遠程服務調用,那么如何理解 RPC、有哪些常見的 RPC 框架、實現一款 RPC 框架需要哪些技術呢?
如何理解 RPC
RPC(Remote Procedure Call)是一種進程間通信方式,百科給出的定義是這樣的:“RPC(遠程過程調用協議),它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議”。
RPC 允許程序調用另一個地址空間的過程或函數,而不用程序員顯式編碼這個遠程調用的細節。即無論是調用本地接口/服務的還是遠程的接口/服務,本質上編寫的調用代碼基本相同。
比如兩臺服務器 A、B,一個應用部署在 A 服務器上,想要調用 B 服務器上應用提供的函數或者方法,由于不在一個內存空間,則不能直接調用,這時候就可以應用 RPC 框架的實現來解決。
RPC 如何實現
早期的遠程服務調用一般是通過 RMI 或 Hessian 等工具實現,以 Java RMI 為例,RMI 是 Java 語言中 RPC 的一種實現方式。
Java RMI(Java 遠程方法調用,Java Remote Method Invocation)是 Java 編程語言里,一種用于實現遠程過程調用的應用程序編程接口。應用 Java RMI,可以讓某個 Java 虛擬機上的對象調用另一個 Java 虛擬機中的對象上的方法。
Java RMI 實現主要依賴 java.rmi 包下面的工具類,具體流程包括繼承 Remote 實現遠程接口,開發業務邏輯,創建 Server 并且注冊遠程對象,客戶端創建 Client 調用遠程方法等。關于 RMI 的實現細節,由于實際開發中很少應用,這里不展開講解了。
以 Java RMI 為代表的的早期 RPC 實現起來比較繁瑣,需要在代碼中直接編碼地址,并且不支持服務治理,比如無法對服務調用進行統計、無法梳理服務依賴情況、無法保證服務上下線時的穩定性等。隨著分布式系統規模的增長,傳統方式已經無法滿足開發需求,于是誕生了一系列的 RPC 服務框架。
RPC 框架代表
開源社區里有許多優秀的 RPC 框架,比如常用的 Dubbo、Thrift、gRPC 等,下面簡單介紹一下這幾款組件。
Apache Dubbo
Dubbo 是阿里巴巴公司開源的一個高性能 Java 分布式服務框架,目前已經成為 Apache 頂級項目。Dubbo 可以通過高性能的 RPC 實現服務的輸出和輸入,支持服務治理,提供了控制臺界面,可以獨立應用,也可以和 Spring 框架無縫集成。
Dubbo 在設計中采用了微內核架構,基于對 Java SPI 機制的擴展實現,Dubbo 對分布式服務調用核心功能都開放了擴展點,包括服務調用的負載均衡策略、序列化協議、傳輸協議等,使用者都可以添加自定義實現。
Dubbo 在國內曾經擁有很高的人氣,是微服務架構的首選,后來隨著 Spring Cloud 的流行,社區一度停更,外部用戶發布了 DubboX 等升級版本。最近,Dubbo 社區又重新活躍,更新后的 Dubbo 也發布了 3.0 預覽版等,并且宣布會在未來的版本中支持更多特性,值得期待。
Google 的 gRPC
gRPC 是 Google 開發的高性能、通用的開源 RPC 框架,gRPC 使用 ProtoBuf 來定義服務,ProtoBuf 是 Google 開發的一種數據序列化協議,性能比較高,壓縮和傳輸效率高,語法也比較簡單。另外,gRPC 支持多種語言,并能夠基于語言自動生成客戶端和服務端功能庫。
Apache Thrift
Thrift 起源于 Facebook,和 Dubbo 一樣,后來被提交 Apache 基金會將 Thrift 作為一個開源項目。Facebook 創造 Thrift 的目的是為了解決 Facebook 各系統間大數據量的傳輸通信,以及系統間語言環境不同需要跨平臺的問題。
Thrift 支持多種編程語言,如 Java、C++、Python、PHP、Ruby 等,可以在多種不同的語言之間通信。應用 Thrift,需要在一個語言無關的 IDL 文件里,定義數據類型和服務接口,然后生成用來構建 RPC 客戶和服務器所需的代碼。
Thrift 主要的優點是跨語言;缺點是,由于需要定義獨立的 IDL 文件,如果對服務進行修改,當數據結構發生變化時,必須重新編輯 IDL 文件、重新編譯和生成相關的代碼,修改起來比較繁瑣。
微博 Motan
Motan 是新浪微博開源的一個 Java RPC 框架,官方文檔對外宣傳在微博平臺已經廣泛應用,每天為數百個服務完成近千億次的調用。
Motan 基于 Java 語言開發,設計和實現與 Dubbo 比較類似,包括服務提供者(RPC Server)、服務調用方(RPC Client)、服務注冊中心(Registry)三個角色。服務端會向注冊中心注冊服務,消費端使用服務需要先向注冊中心進行訂閱,根據注冊中心的返回列表與具體的 服務端建立連接,進行 RPC 通訊。當服務端發生變更的時候,注冊中心也會同步變更,然后同步的通知到消費端。
Motan 也提供了服務治理的功能,包括服務的發現、服務的摘除、高可用及負載均衡。
RPC 框架用到哪些技術
了解了常見的 RPC 框架后,我們來看一下實現一個 RPC 框架需要哪些技術。
如何建立通信
實現分布式服務框架,首先要解決不同節點之間通訊的問題,需要在客戶端和服務器之間建立 TCP 連接,遠程過程調用的所有交換的數據都在這個連接里傳輸。
一般來說,建立通信可以使用成熟的網絡通信框架,比如 Java 語言中的 Netty,這是一個優秀的網絡通信框架。在 Dubbo、Motan 中都應用了 Netty。
如何進行網絡傳輸
建立通信之后,節點之間數據傳輸采用什么協議,也就是選擇什么樣的二進制數據格式組織;傳輸的數據如何序列化和反序列化,比如在 Dubbo 中,傳輸協議默認使用 Dubbo 協議,序列化支持選擇 Hessian、Kryo、Protobuf 等不同方式。
如何進行服務注冊和發現
服務注冊和發現,也就是服務尋址,以 Dubbo 為例,下圖分布式服務典型的尋址和調用過程:
服務注冊,需要服務提供者啟動后主動把服務注冊到注冊中心,注冊中心存儲了該服務的 IP、端口、調用方式(協議、序列化方式)等信息。
服務發現,當服務消費者第一次調用服務時,會通過注冊中心找到相應的服務提供方地址列表,并緩存到本地,以供后續使用。當消費者再次調用服務時,不會再去請求注冊中心,而是直接通過負載均衡算法從 IP 列表中取一個服務提供者調用服務。
上面列舉了一些分布式服務框架的實現要點,除了這些,還有很多技術細節,比如如何實現服務調用,RPC 框架如何和服務層交互,Java 中通過代理實現服務調用,那么代理對象如何解析請求參數、如何處理返回值等。
總結
本文分享了 RPC 遠程服務調用的概念,介紹了常見的 RPC 框架實現,以及 RPC 框架需要關心哪些技術。通過本課時的學習,相信你對 RPC 相關技術有了一個初步認識,如果對其中某個框架感興趣,你可以找一些資料深入了解。