HDFS分析(二)
HDFS中简单的分为:Client,DataNode,NameNode三大类,其中他们之间的通讯一共有这么几种:
Client <=====>NameNode;Client <=====>DataNode;NameNode <======>DataNode;DataNode<=====>DataNode几种,其中涉及到很多网络通讯的封装,也涉及到Hadoop的IPC机制。
他们的通讯如下:
主要类的类图:
HDFS的通讯方面的代码写的不是很优雅,相互依赖太多,只有一点点进行分析
总体
DFSClient与NameNode的通讯使用了Hadoop自身的ipc通讯机制,ipc机制使用了Hadoop自身的IO和序列化方式,没有使用JDK自身的序列化方式
是因为JDK自身的序列化方式过于重量效率不高
NameNode和Datanode都是最顶层的接口VersionedProtocol,实现了该接口就表示这个类将使用Hadoop的RPC机制
Hadoop RPC结构分为Server,Client,以及协议接口和实现
RPC是对外的接口,主要提供了getServer()和getProxy()方法,getServer()为指定协议创建服务器端的实例,在指定的地址和端口上启动服务
getProxy()创建了一个指定协议的服务器端实例的代理
Server端:
ipc.Server类代码比较复杂,内部类比较多,Server处理网络方面使用了NIO Reactor模式
ipc.Server.Listener:服务器端的监听类,监听来自客户端的连接请求,以及为ipc.Server.Listener.Reader注册读事件,创建ipc.Server.Connection实例
ipc.Server.Listener.Reader:ipc.Server.Listener为Reader注册了读事件,Reader读取客户端过来的数据,当读满一个RPC的请求数据的时候处理这些数据生成一个ipc.Server.Call实例,这个实例放入server的BlockingQueue中。
ipc.Server.Handler:一直监听着server的BlockingQueue,如果Reader把Call实例加入的话,Handler从队列里面取出,使用JDK的反射执行相关的方法,
执行完后交有Responder设置Call的response,然后写回给客户端,Responder同步的写回客户端的一个Call的response,其他的Call的结果将有Responder异步写回
基本的类图和流程如下:
Client端:
先看相关的类图:
Client:客户端的实现类
Client.ConnectionId:到RPC服务端对象连接的标识
Client.Connection:到RPC服务端的连接,由Client.ConnectionId进行唯一标识,放在Client的链接池里面
Client.Call:存储客户端的调用参数,以及服务器端后续返回的参数
RPC.Invoker:对InvocationHandler的实现,提供invoke方法,截获RPC客户端对RPC服务端对象的调用
客户端调用的大致流程是:
1.RPC类的getProxy()最终是调用JDK动态代理的方法创建一个VersionedProtocol或者其子接口的代理类,在此创建了InvocationHandler的实现RPC.Invoker的实例
2.在Invoker构造方法中创建Client.ConnectionId,以及根据SocketFactory获得对应的Client实例
3.当客户端调用一个服务器端的方法时,Invoker的invoke方法被调用,invoke方法执行client的call方法
4.Client的call方法中创建了Client.Call实例,获得Client.Connection实例(从连接池中获得或者新建一个,当是新建的一个Connection时,先和服务器端进行连接,
然后写入rpcHeader和ConnectionHeader,从连接池中获得的是不需要设置的),其他还有如Connection的回收这里不表
5.在第4步之后,在connection中写入实际要调用的数据
6.Connection是个线程,在run方法中是同步等待服务器端的返回
7.call实例设置value,返回给调用者
最后给个client和server之间调用示意图: