hadoop 中 hdfs 的 RPC 机制 (简单的分析源码)

来源:互联网 发布:ps拾色器快捷键 mac 编辑:程序博客网 时间:2024/06/05 13:27

RPC 即为远程过程调用(Romote Process Call),即远程调用其他虚拟机中的运行的Java Object,RPC是一个C/S模式,使用的时候包括

服务器代码和客户端代码,RPC就是建立在此基础上的。现在就用一个简单的程序带大家对HDFS的运行机制做一个分析。

MyClient部分:

import java.net.InetSocketAddress;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;

public class MyClient {
    public static void main(String[] args) throws Exception {
        MyBizable proxy = (MyBizable)RPC.getProxy( MyBizable.class,
                MyBiz.BIZ_VERSION,
                new InetSocketAddress(MyServer.SERVER_ADDRESS, MyServer.SERVER_PORT),
                new Configuration());
        
        String result = proxy.hello("world");
        System.out.println(result);
        RPC.stopProxy(proxy);
    }
}

MyServer部分:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.RPC.Server;

public class MyServer {
    public static int SERVER_PORT = 12345;
    public static String SERVER_ADDRESS = "localhost";
    public static void main(String[] args) throws Exception {
        /** Construct an RPC server.
         * @param instance the instance whose methods will be called
         * @param conf the configuration to use
         * @param bindAddress the address to bind on to listen for connection
         * @param port the port to listen for connections on
         */

        Server server = RPC.getServer(new MyBiz(),
                SERVER_ADDRESS, SERVER_PORT, new Configuration());
        server.start();
    }
}

MyBiz 部分:(被远程调用的对象类)

public class MyBiz implements MyBizable{
    public static long BIZ_VERSION = 23456L ;
    public String hello(String param){
        return "hello "+param;
    }
    public long getProtocolVersion(String protocol,long clientVersion){
        return BIZ_VERSION;
    }
}

MyBizable部分:(定义的远程调用的接口)

import org.apache.hadoop.ipc.VersionedProtocol;

public interface MyBizable extends VersionedProtocol{
    public String hello(String param);
}

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

先启动服务端,再启动客户端就能完成整个流程。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

现在开始进行源码分析:

 看似这段代码是FileSystem 与DataNode 直接进行交互的,实际当你深究源码时发现其实是我们“图样图森破”,首先知道 NameNode 实现了ClientProtocol,  DatanodeProtocol, NamenodeProtocol 等接口


下面我们逐个分析这些接口,

  • DFSClient 调用 ClientProtocol

  1. 这个接口是供客户端调用的。这里的客户端不是指的我们自己写的代码,而是hadoop 的一个类叫做 DFSClient。在 DFSClient 中会调用 ClientProtocal 中的方法, 完成一些操作。

  2. 该接口中的方法大部分是对 HDFS 的操作,如 create、delete、mkdirs、rename 等。

  • DataNode 调用 DataNodeProtocol

  1. 这个接口是供 DataNode 调用的。 DataNode 调用该接口中的方法向 NameNode 报告本节点的状态和 block 信息。

  2. NameNode 不能向 DataNode 发送消息,只能通过该接口中方法的返回值向DataNode 传递消息。

  • SecondaryNameNode 调用 NameNodeProtocol

  1. 这个接口是供 SecondaryNameNode 调用的。SecondaryNameNode 是专门做NameNode 中 edits 文件向 fsimage 合并数据的。

下面对DataNode 接口进行一些简单的分析,像分析NameNode一样 先看下源码接口




这里有两个接口,分别是 InterDatanodeProtocol、ClientDatanodeProtocol。这里就不展开分析了。可以根据上面的思路独立分析。

现在再对 HDFS 写数据的做一个简单的分析


FileSystem 的代码内部进行了重载,上面是最终的抽象方法;其读的过程首先是 FileSystem.create ,因为这是一个抽象类,没有实现。只能对应的找它的子类 DistributedFileSystem


. . .   . . .


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


返回值正是创建的对象。这个类有什么神奇的地方吗?我们看一下他的源码


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


可以看到 namenode 其实是 ClientProtocol 接口。那么,这个对象是什么时候创建的呢?


。。。(中间一段就不截了)


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


在整个过程中,DFSClient 是个很重要的类,从名称就可以看出,他表示 HDFS 的 Client,是整个 HDFS 的 RPC 机制的客户端部分。我们对 HDFS 的操作,是通过 FileSystem 调用的DFSClient 里面的方法。FileSystem 是封装了对 DFSClient 的操作,提供给用户使用的。

下面再对HDFS对读数据的过程进行一个简单的分析

现在继续对 FileSystem 类进行剖析,读数据是用的open()方法


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


返回的是一个 DFSInputStream 对象。该对象中含有 NameNode 中的数据块信息。我们看一下这个类的构造方法源码


下面是 openInfo()的源码


下面我们再看下获取数据块的源码


可以看到,获取数据块信息的方法也是通过调用 namenode 取得的。这里的 namenode 属性还是位于 DFSClient 中的。通过前面的分析,我们已经知道,在 DFSClient类中的 namenode 属性是 ClientProtocol。

这就是一个完整的HDFS 读数据的一个过程。其它的就类似 微笑  




原创粉丝点击