基於框架的RPC通訊技術原理解析
RPC的由來
隨著網際網路的發展,網站應用的規模不斷擴大,常規的垂直應用架構已無法應對,分散式服務架構以及流動計算架構勢在必行,亟需一個治理系統確保架構有條不紊的演進。
- 單一應用架構
- 當網站流量很小時,只需一個應用,將所有功能都部署在一起,以減少部署節點和成本。
- 此時,用於簡化增刪改查工作量的 資料訪問框架(ORM) 是關鍵。
- 垂直應用架構
- 當訪問量逐漸增大,單一應用增加機器帶來的加速度越來越小,將應用拆成互不相干的幾個應用,以提升效率。
- 此時,用於加速前端頁面開發的 Web框架(MVC) 是關鍵。
- 分散式服務架構
- 當垂直應用越來越多,應用之間互動不可避免,將核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。
- 此時,用於提高業務複用及整合的 分散式服務框架(RPC),提供統一的服務是關鍵。
例如:各個團隊的服務提供方就不要各自實現一套序列化、反序列化、網路框架、連線池、收發執行緒、超時處理、狀態機等“業務之外”的重複技術勞動,造成整體的低效。
所以,統一RPC框架來解決提供統一的服務。
以下我將分別從如下四個方面詳解RPC。
一:RPC的實現原理
二:PRC架構元件
三:RPC呼叫過程
四:RPC主流框架
一:RPC的實現原理
也就是說兩臺伺服器A,B,一個應用部署在A伺服器上,想要呼叫B伺服器上應用提供的函式/方法,由於不在一個記憶體空間,不能直接呼叫,需要通過網路來表達呼叫的語義和傳達呼叫的資料。
比如說,A伺服器想呼叫B伺服器上的一個方法:
Employee getEmployeeByName(String fullName)
整個呼叫過程,主要經歷如下幾個步驟:
1、建立通訊
首先要解決通訊的問題:即A機器想要呼叫B機器,首先得建立起通訊連線。
主要是通過在客戶端和伺服器之間建立TCP連線,遠端過程呼叫的所有交換的資料都在這個連線裡傳輸。連線可以是按需連線,呼叫結束後就斷掉,也可以是長連線,多個遠端過程呼叫共享同一個連線。
2、服務定址
要解決定址的問題,也就是說,A伺服器上的應用怎麼告訴底層的RPC框架,如何連線到B伺服器(如主機或IP地址)以及特定的埠,方法的名稱名稱是什麼。
通常情況下我們需要提供B機器(主機名或IP地址)以及特定的埠,然後指定呼叫的方法或者函式的名稱以及入參出參等資訊,這樣才能完成服務的一個呼叫。
可靠的定址方式(主要是提供服務的發現)是RPC的實現基石,比如可以採用redis或者zookeeper來註冊服務等等。
- 從服務提供者的角度看:當提供者服務啟動時,需要自動向註冊中心註冊服務;
- 當提供者服務停止時,需要向註冊中心登出服務;
- 提供者需要定時向註冊中心傳送心跳,一段時間未收到來自提供者的心跳後,認為提供者已經停止服務,從註冊中心上摘取掉對應的服務。
- 從呼叫者的角度看:呼叫者啟動時訂閱註冊中心的訊息並從註冊中心獲取提供者的地址;
- 當有提供者上線或者下線時,註冊中心會告知到呼叫者;
- 呼叫者下線時,取消訂閱。
3、網路傳輸
3.1、序列化
當A機器上的應用發起一個RPC呼叫時,呼叫方法和其入參等資訊需要通過底層的網路協議如TCP傳輸到B機器,由於網路協議是基於二進位制的,所有我們傳輸的引數資料都需要先進行序列化(Serialize)或者編組(marshal)成二進位制的形式才能在網路中進行傳輸。然後通過定址操作和網路傳輸將序列化或者編組之後的二進位制資料傳送給B機器。
3.2、反序列化
當B機器接收到A機器的應用發來的請求之後,又需要對接收到的引數等資訊進行反序列化操作(序列化的逆操作),即將二進位制資訊恢復為記憶體中的表達方式,然後再找到對應的方法(定址的一部分)進行本地呼叫(一般是通過生成代理Proxy去呼叫,
通常會有JDK動態代理、CGLIB動態代理、Javassist生成位元組碼技術等),之後得到呼叫的返回值。
4、服務呼叫
B機器進行本地呼叫(通過代理Proxy)之後得到了返回值,此時還需要再把返回值傳送回A機器,同樣也需要經過序列化操作,然後再經過網路傳輸將二進位制資料傳送回A機器,而當A機器接收到這些返回值之後,則再次進行反序列化操作,恢復為記憶體中的表達方式,最後再交給A機器上的應用進行相關處理(一般是業務邏輯處理操作)。
通常,經過以上四個步驟之後,一次完整的RPC呼叫算是完成了。
二:PRC架構元件
一個基本的RPC架構裡面應該至少包含以下4個元件:
1、客戶端(Client):服務呼叫方(服務消費者)
2、客戶端存根(Client Stub):存放服務端地址資訊,將客戶端的請求引數資料資訊打包成網路訊息,再通過網路傳輸傳送給服務端
3、服務端存根(Server Stub):接收客戶端傳送過來的請求訊息並進行解包,然後再呼叫本地服務進行處理
4、服務端(Server):服務的真正提供者
中途插一句
文章寫了一半了,覺得不錯的小夥伴可以給我點點關注,另外想要了解更多Java面試知識點的,也可以關注我一下,我後續也會整理更多關於這一塊的知識點分享出來,另外順便給大家推薦一個Java的交流學習社群:586446657,裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,相信對於已經工作和遇到技術瓶頸的碼友,在這裡會有你需要的內容。
三:RPC呼叫過程
1、服務消費者(client客戶端)通過本地呼叫的方式呼叫服務
2、客戶端存根(client stub)接收到呼叫請求後負責將方法、入參等資訊序列化(組裝)成能夠進行網路傳輸的訊息體
3、客戶端存根(client stub)找到遠端的服務地址,並且將訊息通過網路傳送給服務端
4、服務端存根(server stub)收到訊息後進行解碼(反序列化操作)
5、服務端存根(server stub)根據解碼結果呼叫本地的服務進行相關處理
6、本地服務執行具體業務邏輯並將處理結果返回給服務端存根(server stub)
7、服務端存根(server stub)將返回結果重新打包成訊息(序列化)並通過網路傳送至消費方
8、客戶端存根(client stub)接收到訊息,並進行解碼(反序列化)
9、服務消費方得到最終結果
四:有哪些主流的RPC框架
簡單介紹其中幾種比較典型的:
- RMI
- Hessian
- protobuf-rpc-pro
- Thrift
- Avro
- Dubbo
1.RMI
利用java.rmi包實現,基於Java遠端方法協議(Java Remote Method Protocol) 和java的原生序列化。
2.Hessian
是一個輕量級的remoting onhttp工具,使用簡單的方法提供了RMI的功能。 基於HTTP協議,採用二進位制編解碼。
3.protobuf-rpc-pro
是一個Java類庫,提供了基於 Google 的 Protocol Buffers 協議的遠端方法呼叫的框架。基於 Netty 底層的 NIO 技術。支援 TCP 重用/ keep-alive、SSL加密、RPC 呼叫取消操作、嵌入式日誌等功能。
4.Thrift
是一種可伸縮的跨語言服務的軟體框架。它擁有功能強大的程式碼生成引擎,無縫地支援C + +,C#,Java,Python和PHP和Ruby。thrift允許你定義一個描述檔案,描述資料型別和服務介面。依據該檔案,編譯器方便地生成RPC客戶端和伺服器通訊程式碼。
最初由facebook開發用做系統內個語言之間的RPC通訊,2007年由facebook貢獻到apache基金 ,現在是apache下的opensource之一 。支援多種語言之間的RPC方式的通訊:php語言client可以構造一個物件,呼叫相應的服務方法來呼叫java語言的服務,跨越語言的C/S RPC呼叫。底層通訊基於SOCKET。
5.Avro
出自Hadoop之父Doug Cutting, 在Thrift已經相當流行的情況下推出Avro的目標不僅是提供一套類似Thrift的通訊中介軟體,更是要建立一個新的,標準性的雲端計算的資料交換和儲存的Protocol。支援HTTP,TCP兩種協議。
6.Dubbo
Dubbo是 阿里巴巴公司開源的一個高效能優秀的服務框架,使得應用可通過高效能的 RPC 實現服務的輸出和輸入功能,可以和 Spring框架無縫整合。