RPC框架泛化調用原理及轉轉的實踐
?RPC框架泛化調用功能在網關、接口測試等場景下有著廣泛的需求,本文給各位讀者介紹一下主流的泛化調用實現方式及原理,比較各種實現方案的優缺點,并分享泛化調用在轉轉的實踐。一方面有助于RPC框架使用方理解泛化調用,更好地使用泛化調用;另一方面對于有自研RPC框架需求的開發者在選擇泛化調用實現方案上有一定參考意義。
1、普通RPC調用
基于動態代理技術,RPC框架客戶端做到了調用RPC方法與調用本地方法相同的體驗。一般情況下服務端定義服務接口,并將接口打包到二方jar包發布。服務端在服務進程中實現該接口,而調用方在進程中根據該接口創建動態代理進行調用,與調用本地方法體驗一致。
例如有接口HelloService?,被打包在demo-service-interfaces.jar包中。
服務端依賴demo-service-interfaces.jar?,創建HelloServiceImpl實現該接口。
客戶端同樣依賴demo-service-interface.jar?,創建HelloService的代理類,以下為代碼示例,實際上創建代理類,發送接口、參數,接收返回結果等操作都是封裝在框架內的。
2、網關、接口測試等場景下的需求
由上文可以看到普通的RPC調用需要將接口類(參數和返回值如果是POJO類型同樣需要一起打包)打到一個jar包中,被服務方和調用方共同依賴。這種方式在多大數業務場景中是適用的,且更加方便,因為所依賴的接口jar包是可枚舉的。
但是在一些特殊的場景下依賴接口jar包變得很不方便,比如網關、接口測試平臺等。例如使用http網關代理私有協議RPC請求,如果在網關中依賴接口jar包,那么在新增方法或者接口時網關需要重新編譯上線。而接口測試平臺需要對全公司所有的RPC接口進行測試,將全公司所有的接口jar包添加到測試平臺的依賴中顯然是不可行的。
在這些場景下就誕生了對泛化調用的需求。
3、泛化調用
泛化調用就是在不依賴服務方接口jar包的情況下進行調用,包括對調用方法的泛化、參數的泛化和返回值的泛化。
在沒有接口類依賴的情況下,parameterTypes?需要通過字符串指定,而args?和返回值如果是jdk?內置類型的話與普通調用無異,而如果是POJO類型的話則需要尋找一種通用的表示方法。
下普通RPC調用的序列化與反序列化原理,如下圖所示,實際上序列化框架在將POJO?序列化成字節數組之前需要解析POJO的類結構生成序列化中間體,當然序列化中間體并非一定能在序列化框架中找到對應的類,有時候這個中間體是虛擬的。

普通RPC調用序列化原理
3.1 基于Java Bean的泛化調用
基于Java Bean?的泛化調用是通過統一的Java Bean?描述符(JavaBeanDescriptor?)來描述POJO?對象,它工作在序列化層之上,例如dubbo?支持該種類型的泛化調用,在使用泛化調用時,直接傳遞JavaBeanDescriptor對象作為參數,基本原理如下圖所示。

Java Bean泛化調用
該泛化調用的實現通用性比較強,與底層序列化無關,但是復雜度較高,需要RPC框架處理POJO和JavaBeanDescriptor之間的轉換。
3.2 基于序列化中間體的泛化調用
支持基于序列化中間體的泛化調用的RPC框架典型的如sofa-rpc?,使用了sofa-hessian?序列化框架,sofa-hessian?是在hessian?序列化框架基礎上進行二次開發的,抽象出了序列化中間體,如GenericObject、GenericMap、GenericArray等。
轉轉RPC框架在支持泛化調用時也參考了sofa-hessian?的實現,對hessian序列化框架進行二次開發,并且有所改進。

基于序列化中間體的泛化調用
而json?序列化天然具備序列化中間體,即JsonObject?或者json String?,在使用json?序列化時調用方可以直接將Json Object?或者json String?作為參數代替POJO?進行調用。轉轉RPC框架也支持基于json序列化的泛化調用。
dubbo?除了支持基于Java Bean?的泛化調用,還支持json-protobuf?泛化調用,也就是說調用方可以使用json?描述protobuf?對象,在反序列化時可以將json?反序列為protobuf?對象再轉換成POJO,而這些功能本身是序列化框架所提供,不需要RPC框架做額外的開發支持。
基于序列化中間體的泛化調用與基于Java Bean的泛化調用相比,實現較為簡單,有些序列化框架本身原生就支持,或者對序列化框架做簡單的二次開發即可實現,缺點是與序列化框架耦合。
4、泛化調用在轉轉的實踐
目前泛化調用在轉轉公司應用最廣泛的領域就是接口測試,我們提供了統一的測試API平臺。通過該平臺可以使用http + json的方式實現對任意服務、任意節點、任意方法的調用,而測試API平臺不需要依賴任何服務的接口jar包。并且API平臺也沒有依賴RPC框架jar包,因為轉轉RPC框架實現了在同一個端口上同時兼容私有的二進制協議及公有的http協議,也就是說可以使用http請求來發起RPC調用。
泛化調用在轉轉的應用
同時還支持獲取任意服務、任意節點、任意方法參數及返回值的JsonSchema,如下代碼所示。
未來轉轉的網關也將基于泛化調用進行開發。
5 總結
RPC框架的泛化調用在網關、測試平臺等領域應用廣泛,目前主流的泛化調用實現有基于Java Bean規范的泛化調用和基于序列化中間體的泛化調用,它們的優缺點分別如下:
- 基于Java Bean?的泛化調用:優點是與序列化無關;缺點是RPC框架需要實現JavaBeanDescriptor向POJO的轉換功能,較為復雜。
- 基于序列化中間體的泛化調用:優點是RPC框架實現簡單,序列化框架原生支持或者僅需少量改造;缺點是與特定的序列化框架耦合。
在開發RPC框架時,具體選擇哪種泛化調用實現方式,還需要結合實際情況做出選擇。
關于作者
王建新,轉轉架構部服務治理負責人,主要負責服務治理、RPC框架、分布式調用跟蹤、監控系統等。愛技術、愛學習,歡迎聯系交流。




































