HDFS中DistributedFileSystem的创建
首先,DistributedFileSystem实例的创建途径可由它的构造方法和FileSystem提供的静态方法来创建。但我不建议直接使用构造方法来创建DistributedFileSystem实例,除非你对DistributedFileSystem的内部实现比较的了解。我想,在Apache Hadoop的官网上创建DistributedFileSystem实例的示例永远都会是使用FileSystem提供的静态方法加它的配置文件,使用这种方法就得要注意你的配置文件是否配置正确喽。在配置文件中,fs.default.name和fs.scheme.impl两项一定要相匹配,否则将无法创建DistributedFileSystem实例,fs.default.name的值形式是:scheme://ip:port, fs.scheme.impl的值是一个实现DistributedFileSystem的类权限定名,同时这个实现类必须得有一个无参数的构造方法,否则整个创建构成将失败。其中,scheme可以看作是这个文件系统的标示符,ip:port表示的NameNode节点提供服务的地址,另外非常关键的一点是,标记为红色的scheme要在配置文件中是一样的。还是来个截图吧:
FileSystem会利用JDK的反射机制创建一个DistributedFileSystem实例,然后调用它的initialize()方法。 在类DistributedFileSystem中,有一个重量级的家伙叫DFSClient,而DistributedFileSystem中的绝大多数操作都是交由DFSClient来完成的,这是因为DFSClient全面负责和NameNode的通信。很明显,DFSClient实例的创建实在initialize()方法中完成的。下面就让我来来重点介绍一下DFSClient这个重量级的家伙吧!
从DFSClient的属性中我们可以看出,它们中的许多都是关于和NameNode节点进行通行的配置,在这里我并不打算细将这些,但是有两个属性是不得不讲得,它们分别是namenode和rpcNamenode,它们都是ClientProtocol类型的,这里可能需要提及的是,ClientProtocol接口定义了Client与NameNode进行通信的协议,实际上就是类似于远程调用的stub,namenode和rpcNamenode就是动态生成的ClientProtocol代理类实例,它们中的所有方法都是交给Invoker来执行的,关于Invoker,我待会会仔细的讲解。在这里,有人可能不禁会问,namenode和rpcNamenode有什么区别吗,或者是不是重复了?其实,刚才我还没有来得及说完,rpcNamenode是ClientProtocol的代理类,namenode是rpcNamenode代理类,只是在调用远程方法的时候,若rpcNamenode调用失败,rpcNamenode的代理类namenode会尝试多次调用rpcNamenode的该方法,当然条用次数是由上限的。因此,DFSClient与NameNode的通信就自然而然的要交给namenode来处理了。哦,对了,在这里我还要补充的是,在创建了ClientProtocol的远程代理之后,会马上调用它的getProtocolVesion()方法取回NameNode节点的通信协议版本号,而客户端也有一个版本号,如果两个版本号不匹配的话,整个创建过程将失败。
现在就让我来仔细地探讨探讨Invoker类。在Invoker类中也有个大家伙Client,我们知道,Hadoop在其内部实现了一个简单的基于IPC模型的RPC,而这个Client就是RPC的客户端。当有远程调用是,Invoker会传给Client远程地址、远程方法名、参数,让Client去真正执行远程方法的调用,而自己则会一直等待远程方法结果的返回。那么,Client又是如何实现远程方法的调用的呢?其实这个过程就很简单了,Client首先会根据传入的远程地址与远程Server建立连接Connection,然后再把可序列化的方法信息和参数信息传给Server,之后就等着Server传回可反序列化的执行结果。在这里,Client对Connection做了一些优化,就是根据远程地址、协议类型、用户信息(这些信息被封装到ConnectionId)来缓存该Connection,而不是每次都创建一个连接。另外,Client也不会让Connection总是闲着,而是给它一个最大的空闲时间,当它超过这个时间时,会自动关闭与该远程主机的连接。
为了能更清晰的阐述DistributedFileSystem的创建过程,我将附图一张,来详细描述,当然这张时序图可能不是很规范: