[Hadoop RPC调用入口]
在使用Hadoop RPC基本框架中,主要是通过getProxy来获得一个客户端代理对象,通过这个对象来向服务端发送RPC请求。
getProxy有多个重载方法,最终都是调用到了下面这个函数来进行实现
(来自
org.apache.hadoop.ipc.RPC)
public
static
<T> ProtocolProxy<T> getProtocolProxy(Class<T> protocol,
long
clientVersion,
InetSocketAddress addr,
UserGroupInformation ticket,
Configuration conf,
SocketFactory factory,
int
rpcTimeout,
RetryPolicy connectionRetryPolicy)
throws
IOException {
if
(UserGroupInformation.isSecurityEnabled()) {
SaslRpcServer.init(conf);
}
return
getProtocolEngine(protocol,conf).getProxy(protocol, clientVersion,
addr, ticket, conf, factory, rpcTimeout, connectionRetryPolicy);
}
而在服务端,通过build方法,来构建一个Server对象
(来自
org.apache.hadoop.ipc.RPC.Builder)
/**
* Build the RPC Server.
*
@throws
IOException on error
*
@throws
HadoopIllegalArgumentException when mandatory fields are not set
*/
public
Serverbuild()
throws
IOException, HadoopIllegalArgumentException {
if
(
this
.conf ==
null
) {
throw
new
HadoopIllegalArgumentException(
"conf is not set"
);
}
if
(
this
.protocol ==
null
) {
throw
new
HadoopIllegalArgumentException(
"protocol is not set"
);
}
if
(
this
.instance ==
null
) {
throw
new
HadoopIllegalArgumentException(
"instance is not set"
);
}
return
getProtocolEngine(
this
.protocol,
this
.conf).getServer(
this
.protocol,
this
.instance,
this
.bindAddress,
this
.port,
this
.numHandlers,
this
.numReaders,
this
.queueSizePerHandler,
this
.verbose,
this
.conf,
this
.secretManager,
this
.portRangeConfig);
}
通过上面的两个入口,分别在客户端和服务端生成了进行远程调用所需要的对象。
上面的getProtocolEngine,是获取一个RPC引擎,默认使用的是WritableRpcEngine(新版本貌似改成了ProtobufRpcEngine?),这里使用WritableRpcEngine来进行源码追踪。
下面简述追踪路径:
客户端:WritableRpcEngine.getProxy() ---> Invoker ---> Client
使用了jdk的动态代理,Invoker实现了InvocationHandler接口,其invoke方法的实现,就是通过调用Client的call方法实现的,代码如下
@Override
public
Objectinvoke(Object proxy, Method method, Object[] args)
throws
Throwable {
long
startTime = 0;
if
(
LOG
.isDebugEnabled()) {
startTime = Time.now();
}
ObjectWritable value = (ObjectWritable)
client
.call(RPC.RpcKind.
RPC_WRITABLE
,
new
Invocation(method, args),
remoteId
);
if
(
LOG
.isDebugEnabled()) {
long
callTime = Time.now() - startTime;
LOG
.debug(
"Call: "
+ method.getName() +