1.RPC框架的概念
RPC(Remote Procedure Call)–遠端過程呼叫,通過網路通訊呼叫不同的服務,共同支撐一個軟體系統,微服務實現的基石技術。使用RPC可以解耦系統,方便維護,同時增加系統處理請求的能力。
上面是一個簡單的軟體系統結構,我們拆分出來使用者系統和訂單系統做為服務存在,讓不同的站點去呼叫。
只需要引入各個服務的介面包,在程式碼中呼叫RPC服務就跟呼叫本地方法一樣,我剛接觸到這種呼叫方式的時候頗為驚奇,我明明呼叫的就是java語言方法啊(已java為例,現在RPC框架一般都支援多語言),怎麼就呼叫了遠端的服務了呢??
2.RPC框架的原理解析
最近自己寫了一個簡單的RPC框架KRPC,本文原理分析結合中程式碼,均為該框架原始碼 https://github.com/yangzhenkun/krpc
2.1 流程縱覽
如上圖所示,我將一個RPC呼叫流程概括為上圖中5個流程,左邊3個為客戶端流程,右邊兩個為服務端流程。
下面就各流程進行解析
2.2 客戶端呼叫
服務呼叫方在呼叫服務時,一般進行相關初始化,通過配置檔案/配置中心 獲取服務端地址
使用者呼叫:
一開始接觸RPC呼叫方法肯定就有疑惑,它不是一個介面嗎,直接呼叫應該沒啥效果啊,我也沒有引入實現包。
帶著這個疑惑,我們就進入下一個知識點,動態代理
2.3動態代理
動態代理這東西意如其名,它代理你幫你做事情。
上面我們不說道直接呼叫一個介面中的方法,並且沒有用該介面的實現類呼叫,那麼方法是怎麼生效的呢?
可以看到這個使用者服務這個service是由ProxyFactory代理工程創造的,在該ProxyFactory#create()方法中就跟一個代理處理器繫結在一起了
這個類實現了InvocationHandler介面(JDK提供的動態代理技術),每次去呼叫介面方法,最終都交由該handler進行處理。
這個環節一般會獲取方法的一些資訊,例如方法名,方法引數型別,方法引數值,返回物件型別。
同時這個環節會提供序列化功能,一般的RPC網路傳輸使用TCP(哪怕使用HTTP)傳輸,這裡也要將這些引數進行封裝成我們定義的資料介面進行傳輸。
2.4網路傳輸
我們通過將方法引數進行處理後,就要使用發起網路請求,使用tcp傳輸的就利用socket通訊進行傳輸,這一塊我開源專案中使用的同步堵塞的方案進行請求,也可以使用一些非堵塞方案進行請求,效率會更高一些。
2.5服務端資料接受
這一塊使用netty,可以快速一個高效能、高可靠的一個服務端。
上面程式碼是我專案中使用的服務端程式碼。關於netty網上學習的資料很多,這裡也只是巨集觀的講解RPC原理,就不展開。
2.6真實呼叫
服務端獲取客戶端請求的資料後, 呼叫請求中的方法,方法引數值,通過反射呼叫真實的方法,獲取其返回值,將其序列化封裝,通過netty進行資料返回,客戶端在接受資料並解析,這就完成了一次rpc請求呼叫的全過程。
上面程式碼片段為通過反射呼叫真實方法
2.7 服務端的動態載入
通過2.2到2.6的說明,一次RPC請求過程大致如此,但是一個RPC框架會有很多細節需要處理。
其實在一次請求呼叫前,服務端肯定要先啟動。
服務端作為一個容器,跟我們熟知的tomcat一樣,它可以動態的載入任何專案。所以在服務端啟動的時候,必須要進行一個動態載入的過程。在KRPC中,我使用了URLClassLoader動態載入一個指定路徑的jar包,任何業務服務的實現所依賴的jar包都可以放入該路徑中。
在此我向大家推薦一個架構學習交流群。交流學習群號:575745314 裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化、分散式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
3.總結
一個RPC框架大致需要動態代理、序列化、網路請求、網路請求接受(netty實現)、動態載入、反射這些知識點。現在開源及各公司自己造的RPC框架層出不窮,唯有掌握原理是一勞永逸的。掌握原理最好的方法莫不是閱讀原始碼,自己動手寫是最快的。
注:
原文出處為:微信公眾號 JAVA爛豬皮
作者:喬治