1、背景
本人在這個簡易版的rpc上添加了如下特性:
* 服務異步調用的支援,回調函數callback的支援
* 用戶端使用長連接配接(在多次調用共享連接配接)
* 服務端異步多線程處理rpc請求
2、簡介
rpc,即 remote procedure call(遠端過程調用),調用遠端計算機上的服務,就像調用本地服務一樣。rpc可以很好的解耦系統,如webservice就是一種基于http協定的rpc。
這個rpc整體架構如下:

這個rpc架構使用的一些技術所解決的問題:
服務釋出與訂閱:服務端使用zookeeper注冊服務位址,用戶端從zookeeper擷取可用的服務位址。
通信:使用netty作為通信架構。
spring:使用spring配置服務,加載bean,掃描注解。
動态代理:用戶端使用代理模式透明化服務調用。
消息編解碼:使用protostuff序列化和反序列化消息。
3、服務端釋出服務
使用注解标注要釋出的服務
服務注解
一個服務接口:
一個服務實作:使用注解标注
服務在啟動的時候掃描得到所有的服務接口及其實作:
在zookeeper叢集上注冊服務位址:
這裡在原文的基礎上加了addrootnode()判斷服務父節點是否存在,如果不存在則添加一個persistent的服務父節點,這樣雖然啟動服務時多了點判斷,但是不需要手動指令添加服務父節點了。
4、用戶端調用服務
使用代理模式調用服務:
這裡每次使用代理遠端調用服務,從zookeeper上擷取可用的服務位址,通過rpcclient send一個request,等待該request的response傳回。這裡原文有個比較嚴重的bug,在原文給出的簡單的test中是很難測出來的,原文使用了obj的wait和notifyall來等待response傳回,會出現“假死等待”的情況:一個request發送出去後,在obj.wait()調用之前可能response就傳回了,這時候在channelread0裡已經拿到了response并且obj.notifyall()已經在obj.wait()之前調用了,這時候send後再obj.wait()就出現了假死等待,用戶端就一直等待在這裡。使用countdownlatch可以解決這個問題。
注意:這裡每次調用的send時候才去和服務端建立連接配接,使用的是短連接配接,這種短連接配接在高并發時會有連接配接數問題,也會影響性能。
從zookeeper上擷取服務位址:
每次服務位址節點發生變化,都需要再次watchnode,擷取新的服務位址清單。
5、消息編碼
請求消息:
響應消息:
消息序列化和反序列化工具:(基于 protostuff 實作)
由于處理的是tcp消息,本人加了tcp的粘包處理handler
消息編解碼時開始4個位元組表示消息的長度,也就是消息編碼的時候,先寫消息的長度,再寫消息。
6、性能改進
netty本身就是一個高性能的網絡架構,從網絡io方面來說并沒有太大的問題。
從這個rpc架構本身來說,在原文的基礎上把server端處理請求的過程改成了多線程異步:
netty 4中的handler處理在io線程中,如果handler進行中有耗時的操作(如資料庫相關),會讓io線程等待,影響性能。
個人覺得該rpc的待改進項:
* 用戶端保持和服務進行長連接配接,不需要每次調用服務的時候進行連接配接,長連接配接的管理(通過zookeeper擷取有效的位址)。
* 用戶端請求異步處理的支援,不需要同步等待:發送一個異步請求,傳回feature,通過feature的callback機制擷取結果。
* 編碼序列化的多協定支援。
項目持續更新中。
參考:
輕量級分布式 rpc 架構:http://my.oschina.net/huangyong/blog/361751
你應該知道的rpc原理:http://www.cnblogs.com/lbser/p/4853234.html
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
http://www.cnblogs.com/luxiaoxun/p/5272384.html