The use of Hadoop RPC mechanism

1. Basic concepts of RPC

1.1 Basic Concepts of RPC

  RPC, namely Remote Procdure Call , Chinese name: Remote Procedure Call ;

  (1) It allows a computer program to remotely call a subprogram of another computer without caring about the underlying network communication details, which is transparent to us . Therefore, it is often used in distributed network communication.

The RPC protocol assumes the existence of some transport protocol, such as TCP or UDP, to carry information data between communicating programs. In the OSI network communication model, RPC spans the transport layer and the application layer. RPC makes it easier to develop applications including network distributed multiprogramming.

  (2) The interaction between Hadoop processes is carried out through RPC, such as Namenode and Datanode directly, Jobtracker and Tasktracker, etc.

Therefore, it can be said that the operation of Hadoop is based on RPC .

1.2 Salient Features of RPC

  (1) Transparency : calling programs on other machines remotely is like calling a local method to the user;

  (2) High performance: RPC Server can process multiple requests from Client concurrently;

  (3) Controllability: JDK has provided an RPC framework-RMI, but the PRC framework is too heavyweight and less controllable, so Hadoop RPC implements a custom PRC framework.

1.3 The basic process of RPC

  (1) RPC adopts the C/S mode;

  (2) The client sends a request message with parameters to the server;

  (3) After the server receives the request, it calls the corresponding program according to the sent parameters, and then sends the calculated result to the client;

  (4) The client continues to run after receiving the result;

1.4 RPC mechanism in Hadoop

  同其他RPC框架一样,Hadoop RPC分为四个部分:

  (1)序列化层:Clent与Server端通信传递的信息采用了Hadoop里提供的序列化类或自定义的Writable类型;

  (2)函数调用层:Hadoop RPC通过动态代理以及java反射实现函数调用;

  (3)网络传输层:Hadoop RPC采用了基于TCP/IP的socket机制;

  (4)服务器端框架层:RPC Server利用java NIO以及采用了事件驱动的I/O模型,提高RPC Server的并发处理能力;

  Hadoop RPC在整个Hadoop中应用非常广泛,Client、DataNode、NameNode之间的通讯全靠它了。例如:我们平时操作HDFS的时候,使用的是FileSystem类,它的内部有个DFSClient对象,这个对象负责与NameNode打交道。在运行时,DFSClient在本地创建一个NameNode的代理,然后就操作这个代理,这个代理就会通过网络,远程调用到NameNode的方法,也能返回值。

1.5 Hadoop RPC设计技术

  (1)动态代理

About:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实,代理对象对客户隐藏了实际对象。目前Java开发包中提供了对动态代理的支持,但现在只支持对接口的实现

  (2)反射——动态加载类

  (3)序列化

  (4)非阻塞的异步IO(NIO)

Java NIO原理请参考阅读:http://weixiaolu.iteye.com/blog/1479656

二、如何使用RPC

2.1 Hadoop RPC对外提供的接口

  Hadoop RPC对外主要提供了两种接口(见类org.apache.hadoop.ipc.RPC),分别是:

  (1)public static <T> ProtocolProxy <T> getProxy/waitForProxy(…)

  构造一个客户端代理对象(该对象实现了某个协议),用于向服务器发送RPC请求。

  (2)public static Server RPC.Builder (Configuration).build()

  为某个协议(实际上是Java接口)实例构造一个服务器对象,用于处理客户端发送的请求。

2.2 使用Hadoop RPC的四大步凑

  (1)定义RPC协议

  RPC协议是客户端和服务器端之间的通信接口,它定义了服务器端对外提供的服务接口。

  (2)实现RPC协议

  Hadoop RPC协议通常是一个Java接口,用户需要实现该接口。

  (3)构造和启动RPC SERVER

  直接使用静态类Builder构造一个RPC Server,并调用函数start()启动该Server。

  (4)构造RPC Client并发送请求

  使用静态方法getProxy构造客户端代理对象,直接通过代理对象调用远程端的方法。

三、RPC应用实例

3.1 定义RPC协议

  如下所示,我们定义一个IProxyProtocol 通信接口,声明了一个Add()方法。

public interface IProxyProtocol extends VersionedProtocol {
    static final long VERSION = 23234L; //版本号,默认情况下,不同版本号的RPC Client和Server之间不能相互通信
    int Add(int number1,int number2);
}

  需要注意的是:

  (1)Hadoop中所有自定义RPC接口都需要继承VersionedProtocol接口,它描述了协议的版本信息。

  (2)默认情况下,不同版本号的RPC Client和Server之间不能相互通信,因此客户端和服务端通过版本号标识。

3.2 实现RPC协议

  Hadoop RPC协议通常是一个Java接口,用户需要实现该接口。对IProxyProtocol接口进行简单的实现如下所示:

复制代码
public class MyProxy implements IProxyProtocol {
    public int Add(int number1,int number2) {
        System.out.println("我被调用了!");
        int result = number1+number2;
        return result;
    }

    public long getProtocolVersion(String protocol, long clientVersion)
            throws IOException {
        System.out.println("MyProxy.ProtocolVersion=" + IProxyProtocol.VERSION);
        // 注意:这里返回的版本号与客户端提供的版本号需保持一致
        return IProxyProtocol.VERSION;
    }
}
复制代码

  这里实现的Add方法很简单,就是一个加法操作。为了查看效果,这里通过控制台输出一句:“我被调用了!”

3.3 构造RPC Server并启动服务

  这里通过RPC的静态方法getServer来获得Server对象,如下代码所示:

复制代码
public class MyServer {
    public static int PORT = 5432;
    public static String IPAddress = "127.0.0.1";

    public static void main(String[] args) throws Exception {
        MyProxy proxy = new MyProxy();
        final Server server = RPC.getServer(proxy, IPAddress, PORT, new Configuration());
        server.start();
    }
}
复制代码

  这段代码的核心在于第5行的RPC.getServer方法,该方法有四个参数,第一个参数是被调用的java对象,第二个参数是服务器的地址,第三个参数是服务器的端口 。获得服务器对象后,启动服务器。这样,服务器就在指定端口监听客户端的请求。到此为止,服务器就处于监听状态,不停地等待客户端请求到达。

3.4 构造RPC Client并发出请求

  这里使用静态方法getProxy或waitForProxy构造客户端代理对象,直接通过代理对象调用远程端的方法,具体如下所示:

复制代码
public class MyClient {

    public static void main(String[] args) {
        InetSocketAddress inetSocketAddress = new InetSocketAddress(
                MyServer.IPAddress, MyServer.PORT);

        try {
            // 注意:这里传入的版本号需要与代理保持一致
            IProxyProtocol proxy = (IProxyProtocol) RPC.waitForProxy(
                    IProxyProtocol.class, IProxyProtocol.VERSION, inetSocketAddress,
                    new Configuration());
            int result = proxy.Add(10, 25);
            System.out.println("10+25=" + result);

            RPC.stopProxy(proxy);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
复制代码

  以上代码中核心在于RPC.waitForProxy(),该方法有四个参数,第一个参数是被调用的接口类,第二个是客户端版本号,第三个是服务端地址。返回的代理对象,就是服务端对象的代理,内部就是使用java.lang.Proxy实现的。

  经过以上四步,我们便利用Hadoop RPC搭建了一个非常高效的客户机–服务器网络模型。

3.5 查看运行结果

  (1)启动服务端,开始监听客户端请求

  (2)启动客户端,开始向服务端发请求

  (3)查看服务端状态,是否被调用

SUMMARY:从上面的RPC调用中,可以看出:在客户端调用的业务类的方法是定义在业务类的接口中的。该接口实现了VersionedProtocal接口

  (4)现在我们在命令行执行jps命令,查看输出信息,会出现如下图所示的:

  从上图中可以看到一个java进程,是“MyServer”,该进程正是我们刚刚运行的RPC的服务端类MyServer。因此,大家可以联想到我们搭建Hadoop环境时,也执行过该命令用来判断Hadoop的相关进程是否全部启动。

SUMMARY:那么可以判断,Hadoop启动时产生的5个java进程也应该是RPC的服务端。  

  下面我们观察NameNode的源代码,如下图所示,可以看到NameNode确实创建了RPC的服务端。

复制代码
private void initialize(Configuration conf) throws IOException {
    ......
    // create rpc server
    InetSocketAddress dnSocketAddr = getServiceRpcServerAddress(conf);
    if (dnSocketAddr != null) {
      int serviceHandlerCount =
        conf.getInt(DFSConfigKeys.DFS_NAMENODE_SERVICE_HANDLER_COUNT_KEY,
                    DFSConfigKeys.DFS_NAMENODE_SERVICE_HANDLER_COUNT_DEFAULT);
      this.serviceRpcServer = RPC.getServer(this, dnSocketAddr.getHostName(), 
          dnSocketAddr.getPort(), serviceHandlerCount,
          false, conf, namesystem.getDelegationTokenSecretManager());
      this.serviceRPCAddress = this.serviceRpcServer.getListenerAddress();
      setRpcServiceServerAddress(conf);
    }
    this.server = RPC.getServer(this, socAddr.getHostName(),
        socAddr.getPort(), handlerCount, false, conf, namesystem
        .getDelegationTokenSecretManager());
   ......
}
复制代码

参考资料

(1)thomas0yang,《Hadoop RPC框架》:http://blog.csdn.net/thomas0yang/article/details/41211259

(2)姜维,《Hadoop RPC机制分析》:http://blog.csdn.net/jiangwei0910410003/article/details/21155911 (此文从源码角度分析了RPC,想要深入了解的可以阅读此文)

(3)吴超,《Hadoop的底层架构—RPC机制》:http://www.superwu.cn/2013/08/05/360

(4)东苑草根,《Hadoop RPC基础》:http://www.cnblogs.com/dycg/p/rpc.html

(5)Suddenly,《Hadoop日记Day10-RPC机制》:http://www.cnblogs.com/sunddenly/p/3983193.html

(6)董西成,《Hadoop RPC使用方法》:http://book.51cto.com/art/201312/422043.htm

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325190269&siteId=291194637
RPC