賴歆
(福富軟件,福建 福州 350003)
遠程方法調(diào)用的實現(xiàn)方案研究
賴歆
(福富軟件,福建 福州 350003)
針對分布式系統(tǒng)需要通過網(wǎng)絡(luò)來表達調(diào)用的語義和傳達調(diào)用的數(shù)據(jù)而會遇到的問題,本文對此問題展開探討,首先對跨機間的遠程調(diào)用進行分析,其次從通訊、編碼解碼進行研究,最后了提出具體的解決方案。
遠程方法;通訊;序列化
分布式系統(tǒng)并不像單機系統(tǒng)可以直接通過本地調(diào)用,其基本上由大大小小的服務(wù)組成,并且各種服務(wù)通常會被部署在不同的機器上。由于各種服務(wù)不在同一個內(nèi)存空間,因此不能直接調(diào)用,需要通過網(wǎng)絡(luò)來表達調(diào)用的語義和傳達調(diào)用的數(shù)據(jù)。這時就會遇到兩個問題:
(1)要搭建一個新服務(wù),需要依賴遠程的服務(wù),如何才能調(diào)用遠程服務(wù)?
(2)遠程訪問如何才能滿足高效的性能要求?下文我們將對這兩個問題展開探討。
由于各服務(wù)部署在不同機器,服務(wù)消費方調(diào)用一個服務(wù)就要編寫一堆網(wǎng)絡(luò)通信相關(guān)的代碼,不僅復(fù)雜而且極易出錯。
我們需要一種能像調(diào)用本地服務(wù)一樣調(diào)用遠程服務(wù)的方式,讓網(wǎng)絡(luò)通信中的細(xì)節(jié)對調(diào)用者透明,這樣將大大簡化工作,提高編碼效率,這種方式就是RPC(Remote Procedure Call Protocol)。RPC調(diào)用的流程如圖1所示:
圖1 RPC調(diào)用流程圖
RPC的目標(biāo)是將這些步驟都封裝起來,讓整體的過程細(xì)節(jié)對使用者變得透明。
2.1 實現(xiàn)透明化遠程服務(wù)調(diào)用
通過JAVA的動態(tài)代理技術(shù)封裝通信細(xì)節(jié),讓用戶以類似本地調(diào)用的方式調(diào)用遠程服務(wù)。代理類通過調(diào)用被代理類的相關(guān)方法,提供預(yù)處理、過濾、事后處理等服務(wù),可以使用JDK中的java.lang.reflect.Proxy類來實現(xiàn)動態(tài)代理。
下面簡單介紹用動態(tài)代理進行封裝的示例。調(diào)用者先從RPCProxyClient獲得服務(wù)提供方的接口,當(dāng)執(zhí)行helloServ. hello()方法時會調(diào)用Invoke方法,在代理類的Invoke方法中封裝與遠端服務(wù)通信的細(xì)節(jié)。
/**定義接口并實現(xiàn)方法,它存在于遠端*/
public interface IHello{
void hello();
}
public class Hello implements IHello{
@Override
public String hello(){
System.out.println("Hello.");
return"Hello.";
}
}
/**通過動態(tài)代理封裝屏蔽通信細(xì)節(jié)*/
public class RPCProxyClient implements java.lang.reflect. InvocationHandler{
private Object obj;
public RPCProxyClient(Object obj){
this.obj=obj;
}
public static Object getProxy(Object obj){
return java.lang.reflect.Proxy.newProxyInstance(obj. getClass().getClassLoader(),
obj.getClass().getInterfaces(),new RPCProxy-Client(obj));
}
public Object invoke(Object proxy,Method method, Object[]args)
throws Throwable{
//結(jié)果參數(shù);
Object result=new Object();
//...實現(xiàn)遠程間通信的相關(guān)邏輯
//...
return result;
}
}
/**調(diào)用示例*/
public class Test{
public static void main(String[]args){
IHello helloServ=(hello)RPCProxyClient.getProxy (IHello.class);
helloServ.hello();
}
}
2.2 實現(xiàn)消息的編碼解碼
在Invoke對通信細(xì)節(jié)進行封裝,第一步要確定客戶端和服務(wù)端相互通信的消息結(jié)構(gòu)。一般需要包括幾個主要的信息:
(1)接口名稱:用于服務(wù)端確定調(diào)用哪個接口,如上面例子里接口名是“IHello”。
(2)方法名:用于服務(wù)端確定調(diào)用哪個方法(一個接口內(nèi)可以有多個方法),上面例子里是“hello”。
(3)參數(shù)類型&參數(shù)值。
(4)唯一請求標(biāo)識:遠程調(diào)用可能是同步的,也可能是異步的,當(dāng)設(shè)計工作在異步方式時,需要唯一請求標(biāo)識來明確具體的事務(wù)。
(5)返回值。
確定了消息的數(shù)據(jù)結(jié)構(gòu)后,下一步要考慮序列化與反序列化,以便于將數(shù)據(jù)結(jié)構(gòu)或?qū)ο筠D(zhuǎn)換為二進制串后進行網(wǎng)絡(luò)傳輸,以及從網(wǎng)絡(luò)接收后將二進制轉(zhuǎn)換回對象進行后續(xù)業(yè)務(wù)邏輯處理。
序列化/反序列化的方案很多,每種序列化方案都有優(yōu)點和缺點,從遠程調(diào)用的角度上看,主要看三點:(1)通用性,比如是否能支持Map等復(fù)雜的數(shù)據(jù)結(jié)構(gòu);(2)性能,包括時間復(fù)雜度和空間復(fù)雜度;(3)可擴展性,如果序列化協(xié)議具有良好的可擴展性,支持自動增加新的業(yè)務(wù)字段,刪除老的字段,而不影響老的服務(wù),這將大大提供系統(tǒng)的健壯性。
可以根據(jù)需要選擇互聯(lián)網(wǎng)廣泛使用的hessian、protobuf、avro等成熟的序列化解決方案來搭建。
2.3 實現(xiàn)網(wǎng)絡(luò)通信
消息數(shù)據(jù)結(jié)構(gòu)被序列化為二進制串后,接下來要實現(xiàn)網(wǎng)絡(luò)通信。網(wǎng)絡(luò)通信的實現(xiàn)主要有以下幾種:
(1)同步阻塞(即早期的IO操作):在此種方式下,用戶進程在發(fā)起一個IO操作以后,必須等待IO操作的完成,只有當(dāng)真正完成了IO操作以后,用戶進程才能運行。JAVA傳統(tǒng)的IO模型屬于此種方式,適用于連接數(shù)目比較小且固定的架構(gòu),這種方式對服務(wù)器資源要求比較高,并發(fā)局限于應(yīng)用中。
(2)同步非阻塞(NIO):在此種方式下,用戶進程發(fā)起一個IO操作以后邊可返回做其它事情,但是用戶進程需要定時去詢問IO操作是否就緒,從而引入不必要的CPU資源浪費。在JDK 1.4開始支持此種方式,適用于連接數(shù)目多且連接比較短(輕操作)的架構(gòu),并發(fā)局限于應(yīng)用中。
(3)異步(AIO):此種方式是指應(yīng)用發(fā)起一個IO操作以后,不等待內(nèi)核IO操作的完成,等內(nèi)核完成IO操作以后會通知應(yīng)用程序。在JDK1.7開支持該方式,適用于連接數(shù)目多且連接比較長(重操作)的架構(gòu),充分調(diào)用OS參與并發(fā)操作。
接下來對幾種通信框架gRPC、Java RMI、Netty進行性能驗證,驗證環(huán)境的主要配置參數(shù)見表1:
表1 驗證環(huán)境的主要配置參數(shù)
驗證過程:
(1)編寫驗證程序在2臺主機間調(diào)用,1次調(diào)用算為1次事務(wù)。
(2)逐步加大線程數(shù)測試多線程并發(fā)的性能增長曲線,測試單線程處理多通道的性能增長能力,測試不同長度數(shù)據(jù)下的性能數(shù)據(jù)變化規(guī)律,統(tǒng)計發(fā)送時間和對應(yīng)返回接收時間的時間差作為延遲時間。
(3)觀察運行穩(wěn)定后,收集不同場景下的性能數(shù)據(jù)。
表2 幾種通信架構(gòu)的性能驗證
Netty集群極限性能較高,擴展能力較好,資源利用率較高,適用于異步處理大量通道并發(fā)的業(yè)務(wù)場景;gRPC在ProtoBuf序列化協(xié)議使用上受到一定的限制,采用http2的網(wǎng)絡(luò)利用率較低;RMI的擴展能力較差,通道復(fù)用能力較差,且跨語言調(diào)用能力較弱。
本文對遠程調(diào)用場景進行分析,通過實現(xiàn)調(diào)用透明化、編碼解碼、網(wǎng)絡(luò)通信形成遠程方法調(diào)用的方案,描述方案適用的場景。通過方案原型的測試驗證,更深入地說明方案的特點,實際使用中可根據(jù)不同的場景需要,分別采用不同的方案。
[1]周筱瑜,雷曉俊,陳芳.分布式系統(tǒng)中的通信方式:R PC與R M I [J].電腦與電信,2 0 12(3):3 6-3 9.
[2]劉緒崇,張悅,鐘情花.分布式多用戶遠程控制與密取系統(tǒng)設(shè)計與實現(xiàn)[J].警察技術(shù),2 0 15(6):3 6-3 9.
The Realization of Remote Method Invocation
Lai Xin
(FFCS,Fuzhou 350003,Fujian)
In view of the problem that the distributed system needs to express the semantics of the invocation and communicate the data of the invocation through the network,this paper firstly analyzes the remote invocation across machines;and then researches on the communication,encoding and decoding;and finally puts forward the specific solutions.
remote method;communications;serialize
TP311.52
A
1008-6609(2016)11-0068-03
賴歆(19 79-),男,福建人,系統(tǒng)架構(gòu)工程師,研究方向為電信信息化。