一篇文章了解RPC框架原理
轉載自? ?一篇文章了解RPC框架原理
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()方法中就跟一個代理處理器綁定在一起了
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//構造請求requestRequest request = new Request();....return RequestHandler.request(serviceName, request,returnClass); }這個類實現了InvocationHandler接口(JDK提供的動態代理技術),每次去調用接口方法,最終都交由該handler進行處理。?
這個環節一般會獲取方法的一些信息,例如方法名,方法參數類型,方法參數值,返回對象類型。
同時這個環節會提供序列化功能,一般的RPC網絡傳輸使用TCP(哪怕使用HTTP)傳輸,這里也要將這些參數進行封裝成我們定義的數據接口進行傳輸。
2.4網絡傳輸
我們通過將方法參數進行處理后,就要使用發起網絡請求,使用tcp傳輸的就利用socket通信進行傳輸,這一塊我開源項目中使用的同步堵塞的方案進行請求,也可以使用一些非堵塞方案進行請求,效率會更高一些。
2.5服務端數據接受
這一塊使用netty,可以快速一個高性能、高可靠的一個服務端。
public class ServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf)msg; ?byte[] bytes = new byte[buf.readableBytes()]; ?buf.readBytes(bytes); ?byte[] responseBytes = RequestHandler.handler(bytes);ByteBuf resbuf = ctx.alloc().buffer(responseBytes.length);resbuf.writeBytes(responseBytes);ctx.writeAndFlush(resbuf);} ? ?@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}}上面代碼是我項目中使用的服務端代碼。關于netty網上學習的資料很多,這里也只是宏觀的講解RPC原理,就不展開。
2.6真實調用
服務端獲取客戶端請求的數據后, 調用請求中的方法,方法參數值,通過反射調用真實的方法,獲取其返回值,將其序列化封裝,通過netty進行數據返回,客戶端在接受數據并解析,這就完成了一次rpc請求調用的全過程。
method = clazz.getMethod(request.getMethodName(),requestParamTypes); method.setAccessible(true); result = method.invoke(service, requestParmsValues)上面代碼片段為通過反射調用真實方法
2.7 服務端的動態加載
通過2.2到2.6的說明,一次RPC請求過程大致如此,但是一個RPC框架會有很多細節需要處理。
其實在一次請求調用前,服務端肯定要先啟動。
服務端作為一個容器,跟我們熟知的tomcat一樣,它可以動態的加載任何項目。所以在服務端啟動的時候,必須要進行一個動態加載的過程。在KRPC中,我使用了URLClassLoader動態加載一個指定路徑的jar包,任何業務服務的實現所依賴的jar包都可以放入該路徑中。
?
3.總結
一個RPC框架大致需要動態代理、序列化、網絡請求、網絡請求接受(netty實現)、動態加載、反射這些知識點。現在開源及各公司自己造的RPC框架層出不窮,唯有掌握原理是一勞永逸的。掌握原理最好的方法莫不是閱讀源碼,自己動手寫是最快的。
https://github.com/yangzhenkun/krpc
這是我最近開始寫的一個RPC框架,麻雀雖小五臟俱全,雖然這個框架我還在開發中(還有一些功能沒有完成),歡迎一起討論,star,這個框架中有很多地方可以改進的點。
總結
以上是生活随笔為你收集整理的一篇文章了解RPC框架原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1799 元新低:大疆 Osmo Act
- 下一篇: 华为:预计明年鸿蒙相关岗位需求将达到百万