一:概述
??????? 對系統進行服務化改造,或者構建一個分布式系統,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