基于hessian和netty的RPC框架設計和實現

一:概述

??????? 對系統進行服務化改造,或者構建一個分布式系統,RPC是核心的組件,目前主流的RPC框架有hessian\thrift\ avro等,如果不考慮跨語言的話thrift\ avro使用起來稍顯復雜,要寫IDL序列化配置,hessian又依賴servlet容器,于是使用netty和hessian構建了一個的RPC框架。

??????? hessian是一種二進制的序列化工具,支持C++,python,rubyd等跨平臺,但主要是面向java平臺,其他語言的實現更新很慢。以下是參考網上的hessian序列化性能測試情況,從測試指標來看,跟Protocol Buffers有些差距,但總體表現還是不錯的。

????????????? 序列化


???????????? 反序列化

????? Netty 是一個基于NIO的網絡通訊、服務器端編程框架,使用Netty 可以快速和簡單的開發出一個網絡應用,據非權威測試,在請求應答消息相同的情況下,HTTP方式的TPS是500左右,Netty模式是1.5萬左右,還有更極端的優化到了10W TPS。可見其性能,穩定性和伸縮性都是在業界被普遍認可的。

? ? ? ? RPC的核心就是數據序列化和網絡傳輸,一個典型的PRC服務發布和調用過程主要經歷三個階段,服務導出,服務處理,數據傳輸,如下圖:


二:服務導出

服務定義

服務元數據


導出工具

一般會在服務器啟動前進行導出


????? 以上就是服務導出的過程,首先的定義服務屬性,包括服務名稱,接口,實現類。然后就是服務的元數據,包含接口,方法簽名。所謂導出,其實就是將這些元數據解析出來并進行緩存,以便在調用過程中能夠根據服務名稱找到服務的定義。

三 網絡服務


????? RPC服務器,通過NETTY的ServerBootStrap來定義,可以看到是使用NIO的方式來處理網絡讀寫的(NioServerSocketChannelFactory)。bossThreadFactory用來接收客戶端連接,workerThreadFactory用來執行具體的IO操作。ChannelPipeline是一個消息通道,對消息進行編碼,解碼,壓縮,處理的一個處理器鏈條,應該是Chain of Responsibility。rpcHandler 是進行服務查找,序列化,反序列化,反射調用的處理器,也是整個RPC框架的核心。

???? rpcHandler 繼承自SimpleChannelUpstreamHandler,ChannelUpstreamHandler處理上行的通道事件,并且在流水線中傳送事件。這個接口最常用的場景是攔截IO工作線程產生的事件,傳輸消息或者執行相關的業務邏輯。在大部分情況下,我們是使用 SimpleChannelUpstreamHandler?來實現一個具體的upstream handler,因為它為每個事件類型提供了單個的處理方法。大多數情況下ChannelUpstreamHandler?是向上游發送事件。

?????? rpcHandler 中使用獨立的threadpool是用來處理具體業務的操作,盡量不占用IO線程(Server中的workerThreadFactory)。

???? doSerivce是處理服務請求的方法,通過URL獲取serviceName,再從輸入流中用hessian反序列化獲取AbstractHessianInput,能從中獲取調用方法的名稱,參數列表,參數類型列表等調用方信息。有了這些信息就可以從SerivceExporter中獲取服務定義,找到服務的實現類processorClass,進行反射調用并返回結果。服務處理的過程,其實就是一個HTTP監聽,拿到請求數據,反序列化,反射調用并返回的過程。


四 客戶端

???? 客戶端可以方便的通過Hessian自帶的代理工廠進行實現,用短連接進行同步調用。一般RPC使用異步調用的情況不多,使用HessianProxyFactory可以滿足大部分場景。

??????? 如果RPC中處理的方法耗時較長或者對性有極高的要,則需要使用可復用的長連接進行異步調用,在做這個RPC工具的時候沒有實現異步客戶端,不過在別的項目中用到過異步調用的情況,這里給出實現代碼供參考。

?????????? 以上是一個異步的netty客戶端,大致思路就是,每一次發送請求都會給request一個ID(atomicLong.getAndIncrement()),并實例化一個ResponseFuture進行緩存,當發送同步請求的時候,調用Condition中的await方法,讓線程阻塞,成功返回后,調用Condition中的signal喚醒阻塞的線程。當發送異步請求的時候,不阻塞線程,成功返回后,根據ResponseFuture中的request id找到回調函數,進行回調。最后刪除ResponseFuture緩存。

五? SPRING 支持

????? 現在的企業開發spring有一統天下的趨勢,如果RPC工具不支持SPRING集成,使用起來非常不方便。Spring提供自定義配置支持,通過擴展Schema,就可以完成標簽的配置。

???? 第一步、在classpath下新建META-INF目錄,在目錄中定義nhrpc.XSD

????? 第二部、定義spring.handlers

????? 第三步、定義spring.schemas

第四步、實現命名空間處理器和標簽解析器

????? 命名空間處理器集成自NamespaceHandlerSupport,作用是告訴spring標簽用那個解析器來解析。

?????? 標簽解析器實現自BeanDefinitionParser,重寫其中的doParse方法對標簽進行解析,讀取標簽中的屬性,子標簽等,用來構造BeanDefinition,然后注冊到ParserContext,當BeanDefinition 注冊完畢以后, Spring Bean 工廠就可以隨時根據需要進行實例化該bean 了。

???????? 自定義標簽添加完成后,就可以通過spring的配置方式來進行RPC服務的發布和調用了。

??????? 是不是感覺方便很多。

五,總結

??????? rpc框架的實現過程并不復雜,關鍵點還是在于怎么選擇高效的序列化協議,和高效的網絡傳輸。源碼地址:http://git.oschina.net/wj596/nhrpc



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,993評論 19 139
  • RPC框架遠程調用的實現方式在原理上是比較簡單的,即將調用的方法(接口名、方法名、參數類型、參數)序列化之后發送到...
    謎碌小孩閱讀 3,168評論 0 13
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,974評論 6 342
  • 當愛已成為一種習慣, 曾經的卿卿我我被歲月磨平。 彼此間話語越發稀少, 生活平淡地昏昏欲睡。 有人說這是一種親人式...
    浮生夢中夢閱讀 173評論 0 2
  • 愛上一個非正常人的電影很多:像《時光盡頭的戀人》愛的人不會變老,像《我腦中的橡皮擦》愛的人每天記憶都在減退,像《初...
    王幼稚閱讀 2,243評論 15 36