認識Dubbo與RPC

2023-06-28 06:01:26

關注王有志,分享硬核Java技術的互金摸魚俠
加入Java人的提桶跑路群共同富裕的Java人

開個新坑,和大家一起學習Dubbo 3.X。我們按照一個由淺入深順序來學習,先從使用Dubbo開始,再深入Dubbo的核心原理。

今天我們就從認識Dubbo開始,整體的內容可以分為3個部分:

  • Dubbo是什麼

  • RPC是什麼

  • Dubbo的架構

正式開始前我先疊個甲,通常網上很多資料將RPC稱之為協定,並將RPC與HTTP進行比較,目前來看這已經成為「不太正確」但主流的說法了。而我個人是個原教旨主義者,更傾向使用RPC原初的解釋,因此可能和你看到的部分文章有一定的差別。另外,因個人能力有限,若出現錯誤希望大家不吝賜教。

Tips:RPC的章節主要參考Andrew D. Birrell與Bruce Jay Nelson於1984年發表的論文《Implementing Remote Procedure Calls》,通常認為這篇文章是「現代」RPC的起源(實際上,1976年就有文獻開始討論RPC了)。

Dubbo是什麼?

我們來看Apache Dubbo社群是怎樣描述Dubbo的:

Apache Dubbo是一款RPC服務開發框架,用於解決微服務架構下的服務治理與通訊問題,官方提供了Java、Golang等多語言SDK實現。使用Dubbo開發的微服務原生具備相互之間的遠端地址發現與通訊能力, 利用Dubbo提供的豐富服務治理特性,可以實現諸如服務發現、負載均衡、流量排程等服務治理訴求。Dubbo被設計為高度可延伸,使用者可以方便的實現流量攔截、選址的各種客製化邏輯。

Dubbo是具有高效能,可拓展等特性的RPC框架,除此之外,Dubbo還提供了服務治理的能力。

Dubbo的「野心」不僅僅在於提供一套完整的RPC呼叫及服務治理框架,更是將Dubbo與程式語言解綁,提供了大部分主流語言的版本。

Tips:該圖截自Apache Dubbo社群在B站上釋出的《5分鐘快速瞭解Apache Dubbo》。

RPC是什麼?

既然Dubbo的本質是RPC框架,那麼在繼續深入學習Dubbo前,我們有必要先來了解下RPC是什麼。

RPC(Remote Procedure Call),即遠端過程呼叫。《Implementing Remote Procedure Calls》中是這麼解釋的:

The idea of remote procedure calls (hereinafter called RPC) is quite simple. It is based on the observation that procedure calls are a well-known and well-understood mechanism for transfer of control and data within a program running on a single computer.Therefore, it is proposed that this same mechanism be
extended to provide for transfer of control and data across a communication network.

RPC的思想是基於對單機程式中的傳輸和處理資料的過程呼叫的觀察,並建議將相同的機制拓展到遠端網路通訊上的結果。

是不是有點難理解?沒關係,我們換一個簡單點的說法,來看Sahn Lam在油管視訊《What is RPC? gRPC Introduction》中的解釋,視訊中他通過本地過程呼叫與遠端過程呼叫的對比進行解釋:

A local procedure call is a function call within a process to execute some code.A remote procedure call enables one machine to invoke some code on another machine as if it is a local fuction call from a user's perspective.

這個解釋就非常清晰了,RPC的核心是希望遠端呼叫可以像本地函數呼叫一樣簡單。Birrell與Nelson正是基於此目標,給出了RPC服務的設計參考:

Birrell與Nelson的設計是基於存根(stub,即圖中的User-stub和Server-stub)這個概念的,系統整體包含5個部分:

  • 使用者端,服務呼叫方;

  • 使用者端存根,儲存函數宣告,負責請求引數的打包與響應引數的解包;

  • RPC Runtime,選擇合適的方式(協定)傳輸資料;

  • 伺服器端存根,儲存函數宣告,負責請求引數的解包與響應引數的打包;

  • 伺服器端,服務提供方。

使用者端和伺服器端的開發者只需要從存根中獲取並呼叫目標函數,而無需考慮目標函數所在伺服器的地址和傳輸資料的方式,是非常契合「遠端呼叫可以像本地函數呼叫一樣簡單」這樣的願景的。

好了,到這裡我們已經對「原教旨主義」的RPC有了整體的認知,現在來回答一個不太「正經」的問題:既然有了HTTP為什麼還要RPC?

這是個挺常見的初學誤區,將RPC與HTTP劃上了等號。首先RPC是一種思想(我覺得更像是簡化遠端服務呼叫的目標),而HTTP是應用層的傳輸協定,上圖中「兩個」RPC Runtime傳輸資料時可以使用HTTP,也可以是其它能夠完成資料傳輸的方式。其次,「現代」RPC的理論誕生於1984年,而HTTP是1989年發起的,因此這個問題反過來問還顯得稍微合理些。最後,HTTP的誕生的目的是接收和釋出HTML頁面,即在瀏覽器與伺服器端之間進行資料的傳輸,而不是應用在兩個伺服器端之間的資料傳輸。

Tips

  • Sahn Lam和Alex Xu是油管頻道ByteByteGo的管理者,擁有有43萬粉絲,另外他們也是《System Design Interview》的作者;

  • RPC的系統設計圖截自《Implementing Remote Procedure Calls》;

  • 實際的專案中,沒有嚴格的使用者端與伺服器端的區分,服務都可以提供對外的介面,也可以使用外部服務的介面。

Dubbo的架構

Dubbo 3.0開始,Dubbo的官方檔案使用了新的抽象架構:

將Dubbo從整體劃分了兩層:

  • Dubbo資料面:提供RPC功能的核心部分,通過RPC協定進行通訊,定義了呼叫規範,完成了資料互動的編碼和解碼功能做;

  • 服務治理控制面:服務治理的抽象,包含了註冊中心,流量管控策略,Dubbo Admin控制檯等。

Dubbo 3.0之前,官方給出過一張非常複雜的Dubbo 2.X的設計圖(以下的部分是官方原文):

圖例說明

  • 圖中左邊淡藍背景的為服務消費方使用的介面,右邊淡綠色背景的為服務提供方使用的介面,位於中軸線上的為雙方都用到的介面;

  • 圖中從下至上分為十層,各層均為單向依賴,右邊的黑色箭頭代表層之間的依賴關係,每一層都可以剝離上層被複用,其中,Service和Config層為API,其它各層均為SPI;

  • 圖中綠色小塊的為擴充套件介面,藍色小塊為實現類,圖中只顯示用於關聯各層的實現類;

  • 圖中藍色虛線為初始化過程,即啟動時組裝鏈,紅色實線為方法呼叫過程,即執行時調時鏈,紫色三角箭頭為繼承,可以把子類看作父類別的同一個節點,線上的文字為呼叫的方法。

Dubbo提供了非常豐富的介面,這些都是Dubbo的可被使用者自定義的拓展點。Dubbo自身也採用了Microkernel+Plugin(微核心+拓展)的模式,Microkernel只負責組裝Dubbo對Plugin的預設實現。

各層說明

  • config設定層:對外設定介面,以ServiceConfigReferenceConfig為中心,可以直接初始化設定類,也可以通過Spring解析設定生成設定類

  • proxy服務代理層:服務介面透明代理,生成服務的使用者端Stub和伺服器端Skeleton, 以ServiceProxy為中心,擴充套件介面為ProxyFactory

  • registry註冊中心層:封裝服務地址的註冊與發現,以服務URL為中心,擴充套件介面為RegistryFactoryRegistryRegistryService

  • cluster路由層:封裝多個提供者的路由及負載均衡,並橋接註冊中心,以Invoker為中心,擴充套件介面為ClusterDirectoryRouterLoadBalance

  • monitor監控層:RPC呼叫次數和呼叫時間監控,以Statistics為中心,擴充套件介面為MonitorFactoryMonitorMonitorService

  • protocol遠端呼叫層:封裝RPC呼叫,以InvocationResult為中心,擴充套件介面為ProtocolInvokerExporter

  • exchange資訊交換層:封裝請求響應模式,同步轉非同步,以RequestResponse為中心,擴充套件介面為ExchangerExchangeChannelExchangeClientExchangeServer

  • transport網路傳輸層:抽象Mina和Netty為統一介面,以Message為中心,擴充套件介面為ChannelTransporterClientServerCodec

  • serialize資料序列化層:可複用的一些工具,擴充套件介面為SerializationObjectInputObjectOutputThreadPool

有些文章會將Service納入Dubbo的層級結構中,但實際上Service是使用者業務邏輯的部分,嚴格意義上並不是Dubbo自身的組成。

支援協定

協定是RPC框架的核心功能,定義了資料的傳輸格式,除了資料本身外,還應包含控制資訊,如:序列化方式,超時時間等。

Dubbo支援了非常多的協定,在這裡我將它們分成5類:

不要看到Dubbo支援了這麼多協定就害怕,它雖然支援的多,但我們不必每個協定都深入。未來我們在學習到協定的部分是,會重點的學習Dubbo協定,Dubbo 3.X主推的Triple協定以及支援HTTP/2的gRPC,其餘協定我們大致瞭解其特性即可。

Tips:實際上Dubbo 2.X的官方檔案中有非常詳細的設計檔案,不知道為什麼Dubbo 3.0中刪除了這部分內容。

結語

好了,到目前為止希望你能夠建立起一個對Dubbo設計的整體認知。設計雖然複雜,支援的協定雖然很多,但我們今天的目的不是「一文弄懂」。我們以理解RPC和Birrell與Nelson給出的設計為主,其次我們需要建立對Dubbo的設計的整體認知,看看它Dubbo在Birrell與Nelson的基礎上做出了哪些拓展。如果有興趣的話,可以參考Birrell與Nelson給出的架構來設計自己的RPC服務,需要考慮如何將服務儲存到存根中?使用哪種方式進行互動?互動的資料結構該如何設計?

下一篇,我們一起來使用Duubbo,掌握Dubbo的應用。如果本文對你有幫助的話,請多多點贊支援。最後歡迎大家關注分享硬核技術的金融摸魚俠王有志,我們下次再見!