HDFS 的 RPC 机制


4.6. HDFS 的 RPC 机制
RPC 是远程过程调用 (Remote Procedure Call),即远程调用其他虚拟机中运行的 java
object。 RPC 是一种客户端/服务器模式, 那么在使用时包括服务端代码和客户端代码, 还有
我们调用的远程过程对象。


HDFS 的运行就是建立在此基础之上的。本章通过分析实现一个简单的 RPC 程序来分析
HDFS 的运行机理。本节难度偏大,读者可以在第二、三遍阅读本书时掌握即可。
下面的代码是服务端代码 。

核心在于第 5 行的 RPC.getServer 方法, 该方法有四个参数, 第一个参数是被调用的 java
对象, 第二个参数是服务器的地址, 第三个参数是服务器的端口。 获得服务器对象后, 启动
服务器。这样,服务器就在指定端口监听客户端的请求。
下面的代码是被调用的远程对象类。

被调用的远程对象实现了接口 MyBizable,这里面有两个方法被实现,一个就是 hello
方法, 另一个是 getProtocalVersion 方法。这个 hello 方法内部有个输出语句。
下面的代码是远程调用类的接口定义。

 

这个接口中的方法就是刚才的 Biz 中实现的方法。接口继承的 VersionedProtocal, 是
hadoop 的 RPC 的接口,所有的 RPC 通信必须实现这个一接口,用于保证客户端和服务端的
端口一致。服务端被调用的类必须继承这个接口 VersionedProtocal。
下面是客户端代码,这里使用的调用对象的接口。

以上代码中核心在于 RPC.getProxy(),该方法有四个参数,第一个参数是被调用的接口
类, 第二个是客户端版本号, 第三个是服务端地址。 返回的代理对象, 就是服务端对象的代
理,内部就是使用 java.lang.Proxy 实现的。
运行时,先启动服务端,再启动客户端。读者可以服务端和客户端输出信息。
从上面的 RPC 调用中,可以看出: 在客户端调用的业务类的方法是定义在业务类的接
口中的。该接口实现了 VersionedProtocal 接口。
现在我们在命令行执行 jps 命令,查看输出信息,如图 5-1 所示。

可以看到一个 java 进程,是“MyServer”,该进程正是我们刚刚运行的 rpc 的服务端类
MyServer。大家可以联想到我们搭建 hadoop 环境时,也执行过该命令用来判断 hadoop 的
进程是否全部启动,如图 3-。那么可以判断, hadoop 启动时产生的 5 个 java 进程也应该是
RPC 的服务端。 我们观察 NameNode 的源代码, 如图 5-2, 可以看到 NameNode 确实创建了
RPC 的服务端。

4.7. NameNode 的接口分析
由 5.1 节分析, 可以看到 NameNode 本身就是一个 java 进程。观察图 5-2 中 RPC.getServer()
方法的第一个参数,发现是 this,说明 NameNode 本身就是一个位于服务端的被调用对象,
即 NameNode 中的方法是可以被客户端代码调用的。根据 RPC 运行原理可知, NameNode
暴露给客户端的方法是位于接口中的。
我们查看 NameNode 的源码,如图 5-3 所示。

可以看到 NameNode 实现了 ClientProtocalDatanodeProtocalNamenodeProtocal 等接
口。下面我们逐一分析这些接口。
DFSClient 调用 ClientProtocal
这个接口是供客户端调用的。这里的客户端不是指的我们自己写的代码,而是
hadoop 的一个类叫做 DFSClient。在 DFSClient 中会调用 ClientProtocal 中的方法, 完
成一些操作。
该接口中的方法大部分是对 HDFS 的操作, 如 createdeletemkdirsrename 等。
DataNode 调用 DatanodeProtocal
这个接口是供 DataNode 调用的。 DataNode 调用该接口中的方法向 NameNode 报告
本节点的状态和 block 信息。
NameNode 不能向 DataNode 发送消息,只能通过该接口中方法的返回值向
DataNode 传递消息。
SecondaryNameNode 调用 NamenodeProtocal
这个接口是供 SecondaryNameNode 调用的。 SecondaryNameNode 是专门 做
NameNode edits 文件向 fsimage 合并数据的。
4.8. DataNode 的接口分析
按照分析 NameNode 的思路,看一下 DataNode 的源码接口,如图 5-4 所示。

这里有两个接口,分别是 InterDatanodeProtocal、 ClientDatanodeProtocal。这里就不展
开分析了。读者可以根据上面的思路独立分析。
4.9. HDFS 的写数据过程分析
我们通过 FileSystem 类可以操控 HDFS, 那我们就从这里开始分析写数据到 HDFS 的过程。
在我们向 HDFS 写文件的时候,调用的是 FileSystem.create(Path path)方法,我们查看这
个方法的源码,通过跟踪内部的重载方法,可以找到如图 5-5 所示的调用。

这个方法是抽象类, 没有实现。 那么我们只能向他的子类寻找实现。 FileSystem 有个子
类是 DistributedFileSystem ,在我们的伪分布环境下使用的就是这个类。我们可以看到
DistributedFileSystem 的这个方法的实现,如图 5-6 所示。

在图 5-6 中, 注意第 185 行的返回值 FSDataOutputStream。 这个返回值对象调用了自己
的构造方法, 构造方法的第一个参数是 dfs.create()方法。 我们关注一下这里的 dfs 对象是谁,
create 方法做了什么事情。现在进入这个方法的实现,如图 5-7 所示。

 

在图 5-7 中, 返回值正是第 713 行创建的对象。 这个类有什么神奇的地方吗?我们看一
下他的源码,如图 5-8 所示。

在 图 5-8 中 , 可 以 看 到 , 这 个 类 是 DFSClient 的 内 部 类 。 在 类 内 部 通 过 调 用
namenode.create()方法创建了一个输出流。 我们再看一下 namenode 对象是什么类型, 如图
5-9 所示。

在图 5-9 中, 可以看到 namenode 其实是 ClientProtocal 接口。 那么, 这个对象是什么时
候创建的那?如图 5-10 所示。

可以, namenode 对象是在 DFSClient 的构造函数调用时创建的,即当 DFSClient 对象存
在的时候, namenode 对象已经存在了。
至此,我们可以看到,使用 FileSystem 对象的 api 操纵 HDFS,其实是通过 DFSClient 对
象访问 NameNode 中的方法操纵 HDFS 的。这里的 DFSClient 是 RPC 机制的客户端, NameNode
是 RPC 机制的服务端的调用对象,整个调用过程如图 5-11 所示。

在整个过程中, DFSClient 是个很重要的类, 从名称就可以看出, 他表示 HDFS 的 Client,
是整个 HDFS 的 RPC 机制的客户端部分。我们对 HDFS 的操作,是通过 FileSsytem 调用 的
DFSClient 里面的方法。 FileSystem 是封装了对 DFSClient 的操作,提供给用户使用的。
4.10. HDFS 的读数据过程分析
我们继续在 FileSystem 类分析,读数据使用的是 open(…)方法,我们可以看到源码,如

在图 5-12 中, 返回的是 DFSClient 类中 DFSDataInputStream 类, 显而易见, 这是一个内
部类。这个内部类的构造函数,有两个形参,第一个参数是 dfs.open(…)创建的对象。我们
看一下方法的源码,如图 5-13 所示。

在图 5-13 的实现中,返回的是一个 DFSInputStream 对象。该对象中含有 NameNode 中
的数据块信息。我们看一下这个类的构造方法源码,如图 5-14 所示。

在图 5-14 中,这个构造方法中最重要的语句是第 1834 行,打开信息,从第 1840 行开
始是 openInfo()的源代码, 截图显示不全。 注意第 1841 行, 是获取数据块的信息的。 我们查
看这一行的源代码,如图 5-15 所示。

从图 5-15 中可以看到,获取数据块信息的方法也是通过调用 namenode 取得的。这里
的 namenode 属性还是位于 DFSClient 中的。通过前面的分析,我们已经知道,在 DFSClient
类中的 namenode 属性是 ClientProtocal。
至此,读者应该能够自己画出类之间的调用过程了。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM