如何自己實現一個RPC框架?

開源的RPC框架,大家都用過Dubbo,底層源碼大部分人爲了面試也都看過了,服務暴露過程和服務引用過程,服務調用流程等,但那都是多多少少不那麼純粹,就算是自己學習,也終究是站在巨人的肩膀上,你的思路在你看Dubbo源碼的那一刻就被Dubbo的路子限制住了,讓你覺得,RPC框架,就只能這麼幹,如果你自己實現,你要怎麼實現?

 

首先

RPC框架和微服務框架:個人認爲,RPC框架強調的是遠程過程調用這一功能的實現,但是像網關/服務降級/限流/熔斷等,只是RPC框架的衍生品,屬於生態周邊。比如Dubbo,在熔斷方面很弱,但是專業事情交給專業人,hystrix和sentinel不就是專門做限流熔斷的嗎?而SpringCloud,則是一整套解決方案,不僅僅侷限於RPC框架了,人家從前到後都有單獨的模塊,網關zool,熔斷器hystrix,客戶端feign,註冊中心eureka等,SpringCloud更像一個微服務框架,強調的是微服務一整套解決方案,不僅僅RPC。

 

正題

RPC框架的基本是什麼?是通訊,基於TCP傳輸的模型有什麼:BIO和NIO,成熟的框架有Netty和Mina。

 

通訊只是基本手段,那麼下一步要考慮的問題就是,數據傳輸怎麼做?要傳輸什麼樣的數據?

我們初學都學過BIO,寫過聊天室,傳輸的數據都是個String,輸入字符串,輸出字符串,簡單。

如果我們要傳輸對象呢?可以用ObjectInputStream和ObjectOutputStream + ByteArrayInputStream和ByteArrayOutputStream來實現對象的序列化和反序列化。

如果我們要求,在客戶端傳遞的任何對象比如User,到了服務端都能自動變成對象類型User,而不是Object呢?那麼我們是不是可以傳遞對象的Class信息,到了服務端,利用獲取到的Class信息,把Object加工成User對象。

如果我們要求,客戶端拿着一份接口,調用裏面的方法,就能拿到服務端那邊接口的實現類返回的數據,就像本地調用一樣絲滑呢?那麼這就是RPC調用的需求。

1. 客戶端和服務端建立好通訊,保證道路暢通

2. 客戶端這邊調用接口的方法的時候,我們要收集好接口+方法信息+參數信息,打包好(收集數據+序列化)併發送。

3. 服務端這邊呢,接收到客戶端的數據,拆包(反序列化),拿到接口信息,找到該接口的實現類;拿到方法信息,找到實現類中對應的方法;拿到參數信息,傳入具體的參數值,調用實現類中的方法;實現類返回數據,服務端將返回數據和返回類型打包(序列化),發送給客戶端。

4. 客戶端拿到服務端返回的數據,展示給用戶。

這只是個簡單的思路,實際上裏面還有很多細節,比如:

1. 併發情況下,數據傳輸會亂序。

2. 如何知道,服務端返回的數據,是給哪一個方法的?

3. 客戶端的接口是無法實例化的,接口怎樣調用?調用之後如何與客戶端搭上關係?

4. 如何確定客戶端要調用服務端的哪一個方法,確定之後,用反射調用嗎?

5. 客戶端超時了怎麼辦?

數據傳輸做好之後,客戶端和服務端接口提供與消費的同步怎麼做?也就是服務註冊與發現,因爲現實中,不可能單客戶端和單服務端。

這部分還是很好理解的,服務註冊與發現需要一個註冊中心,註冊中心就是一個第三方。類似於買家/買家/中間商的關係,買家和賣家不直接接觸,完全靠中間商互通有無。

這裏可以說一下CAP:

CAP分別是(數據)一致性,(服務器)可用性和分區容錯性(分佈式系統中在部分斷網的情況下仍然可以完全正常的工作)。那麼一個分佈式系統中,P是必須的,剩下就在CA中選一個。

Zookeeper只能保證CP,一致性和分區容錯性:不能保證可用性(A)是因爲Master選舉的過程中,整個集羣是不可用的。

Eureka可以保證AP,可用性和分區容錯性:當單個服務器掛掉的情況下,我還可以請求其它服務器(可用性),只是當前服務器的數據可能不是最新的(一致性)

我覺得一個最基本,最純粹的RPC流程是這樣的:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章