Hadoop RPC框架原理
RPC是远程过程调用(Remote Procedure Call)的缩写形式。RPC主要目的是能让应用层可以像调用本地方法一样调用远程方法。既然是远程调用,肯定是采用了c/s架构。我们可以先分析一下client和server分别要完成什么事情。
Client:当应用层调用方法时,肯定要先建立连接,然后把方法和参数都通过socket传输给server,server返回数据以后,把数据format成方法的返回值,返回给应用层。以调用方法为中心,本质上是对该方法加强(方法前后都做了事情),所以这边用代理模式实现比较合适。由于调用方法肯定会有很多,我们可以把调用方法的集合(java里面就是调用方法所在的java类)叫做protocol。
Server:server接到请求以后,不同的protocol肯定会有不同的处理器,在RPC.Server中叫做protocolimpl。
Client把方法和参数转换成发送字节流以及server应答字节流转换成返回值对象可以有多种实现方法,可以把不同的实现叫做不同的RpcEngine。
RPC类(org.apache.hadoop.ipc.RPC)分析
从上面的分析以后就可以比较容易的理解RPC类中概念:
Protocol:代理方法的集合。由于client和server都会实现,所有以Interface出现,接口上会打上ProtocolInfo注解,包含ProtocolName和ProtocolVersion。
RpcEngine:有ProtobufRpcEngine和WritableRpcEngine两种实现。每种Protocol都会定义使用哪种处理引擎。
Server:父类是org.apach.hadoop.ipc.server,有server端的主要实现。由于每个server都可以有多个protocol以及protocolimpl,所有server会有一个protocol实现类集合,集合第一层是RpcKind(RpcEngine类型),第二层是protocolMap,key值由ProtocolName和ProtocolVersion计算得出。
ProtobufRpcEngine类分析
Hadoop中的通信基本都是使用的ProtobufRpcEngine,所有这边主要对此类做分析。
由于ProtobufRpcEngine主要处理的Protobuf的方法,即Message method(Message),入参和返回值都是Message。这种方法的集合一般不手写,而是通过proto自动编译生成,在hadoop里面一般都是编译以后的proto类中的blockingInterface,由于此类是Protocol必须打上ProtocolInfo,但是编译的类是不可能打注解的,所以正常会创建一个Interface来继承blockingInterface,再在此Interface上打上注解。
Client端:从Hadoop RPC框架原理分析中,可以了解到Client端主要使用代理实现,既然使用代理,核心处理肯定在java.lang.reflect.InvocationHandler的实现类里面。在ProtobufRpcEngine很容易找到Invoker类,此类是RpcInvocationHandler的实现类,而RpcInvocationHandler就是InvocationHandler的子类。阅读Invoker.invoke,就能了解client发送逻辑。
Client Request由RequestHeaderProto作为Head和参数Message作为Body构成,写入流的方式都是用过proto.writeDelimitedTo方法。RequestHeaderProto由MethodName,protocolName和protocolVersion组成。Response的处理就是Return Message.writeDelimitedTo的解析。
Server端:Rpc.RpcInvoker是所有处理引擎的父类,ProtoBufRpcInvoker是此类的子类,此类的call方法就是server端处理流程。主要是根据RequestHeaderProto中的protocolName和protocolVersion组成key值,找到protocol处理类protocolimpl。然后根据RequestHeaderProto中的Method和body中的参数Message,用反射的方式执行protocolimpl.method(message),拿到return message,最后通过message.writeDelimitedTo返回给客户端。
应用层分析
应用层主要调用的方法是method(params)这种,根据上面的分析,需要转换成Message method(Message)这种,所以在client端一般会有一个protocol的包装类来完成此操作。这种包装类本质上也是方法的集合,也可以称作protocol,一般也有个protocol接口类。为了不和上面混淆,底层的protocol我们可以称作protocolPB,应用层的称之为protocol。
Hdfs getBlockLocations全流程分析
了解以上所有概念以后,分析Hdfs的namenode请求就极其简单了。
ClientProtocol:应用层protocol
ClientNamenodePB:通信层protocolPB
ClientNamenodeProtocolTranslatorPB:ClientProtocol客户端实现类,也是ClientNamenodePB的包装类。主要实现src,offset,length转换为GetBlockLocationsRequestProto以及返回proto转换为方法的返回值。
NameNodeRPCServer:即是接受server也是ClientProtocol的实现。
ClientNamenodeProtocolServerSideTranslatorPB:ClientNamenodePB实现类,主要是GetBlockLocationsRequestProto转换为src,offset,length以及底层方法返回值转换为ResponseProto。功能上对应ClientNamenodeProtocolTranslatorPB。
Namesystem:server方法的真正实现类。