hadoop RPC 技术架构和demo实例

一,Hadoop RPC 概述

      相信每个在学习分布式应用时候,都会好奇节点之间的通信是怎样的。节点之间的交互在整个Hadoop生态系统中扮演非常通用和基础的角色,包括HDFS、MapReduce、HBase以及YARN内部各组件之间的RPC交互几乎都依赖大致相同的IPC框架实现,比如心跳机制,NN对于DN的管理指令, Client 和 DN节点的数据流传输等等。

分析Hadoop的IPC实现原理对理解整个Hadoop生态系统内各系统都会有极大的帮助。

    RPC具有以下特点:

  • 透明性。所有 RPC 框架的基本特性,对用户屏蔽了网络通信过程。
  • 高性能。Hadoop 各个子系统均采用 Master/Slave 架构,Master 作为一个 RPC Server,负责处理所有 Slave 发送的请求,需要能够高效的处理多个并发 RPC 请求。
  • 可控性。JDK 自带的 RPC 框架(RMI)过于重量级,用户可控之处太少,如:网络连接、超时和缓存等难以修改。因此 Hadoop 实现了轻量级的可控性更强的 RPC 框架。

二, 具体的调用实现

  既然说到了Hadoop集群内的RPC,具体的调用有哪些呢? RPC 的具体调用的功能,都是ProtocalVersioned 接口的实现类,类中的方法实现了调用逻辑。Hadoop有多个模块,这里拿HDFS 文件系统中几个协议举例:

1, ClientProtoclo  定义客户端与namenode节点间的接口,用于客户端对文件系统的所有操作,读写都需要与该接口交互。包括hdfs文件读写的相关操作,hdfs命名空间,快照,缓存相关的操作。

2,ClientDatanodeProtocol  主要用户客户端获取datanode节点信息

3,DatanodeProtocol  datanode与namenode间的通信接口,包括namenode通过该接口中的方法返回向datanode下发指令。datanode则是通过该接口向namenode进行注册,汇报块信息和缓存信息。比如调用blockReport()汇报datanode上存储的所有数据块信息,最后调用cacheReport()汇报datanode缓存的所有数据块。

 

三,技术架构

    通俗的语句概括就是: A进程调用远程机器 B进程里的类方法,并返回结果。A进程把 需要调用的 “类的方法名和参数 ” 放入一个对象(CALL对象),并序列化,通过TCP协议传输到其他节点的进程中,服务器接收后,反序列化为Java对象,通过反射,调用服务器端的该类的方法。返回值然后返回给A进程。

   其中使用的底层技术包括:

         1,序列化,反序列化过程模型 :  Hadoop内部自己的序列化框架

         2,TCP连接通信模型,( 数据网络IO模型 Socket -> IO模型升级Nio ) TCP协议

    3,Java动态代理 和反射     功能是在运行状态中,获取类的方法功能。 
    4,Reactor线程模型   该模型处理大量远程 IO(RPC)任务的读取,保存和处理过程,实现高并发 。通俗的说,在SERVER端 ,有多个接待员 (Receiver)和多多个服务员Handler 。 服务端(ipc.Server)基于Reactor设计模式,作为自己的高并发解决方案。

        5,Java NIO : 多路复用IO模型    (NIO 是 网络IO任务的高并发解决方案; 服务器端Reactor模型是请求达到Server后,处理“请求”的高并发方案)

 

   ( 以上RPC的底层依赖技术,本文不详细讲解,主要理解RPC上层实现过程)

 

图一:组件图

 

图二:总体运行图 

 

三,应用层代码实例

这里直接使用Hadoop-common  2.7.0包,开发一个使用Hadoop RPC功能入门实例。

引入包: 只要一个

<dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-common</artifactId>
      <version>2.7.0</version>
    </dependency>

1,自定义的协议接口

public interface  ClientProtocol extends VersionedProtocol {  //建立自己的协议接口,定义RPC行为
    public static final long versionID=1111L;

    String echo(String value);
}

2,协议接口实现类

package org.example;

import org.apache.hadoop.ipc.ProtocolSignature;
import java.io.IOException;

public class ClientProtocolImpl implements ClientProtocol {

    @Override
    public long getProtocolVersion(String arg0, long arg1) throws IOException {
        // TODO Auto-generated method stub
        return ClientProtocol.versionID;
    }

    @Override
    public ProtocolSignature getProtocolSignature(String arg0, long arg1, int arg2) throws IOException {
        return new ProtocolSignature(ClientProtocol.versionID,null);
    }

    @Override
    public String echo(String value) {   //实现自定义的协议接口,具体化行为方法
        return "hello "+value; }  

}

3, 客户端

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

import java.io.IOException;
import java.net.InetSocketAddress;

public class Client {

    public static void main(String[] args) throws IOException {
        ClientProtocol proxy = (ClientProtocol) RPC.getProxy(  //建立proxy 代理对象,包含协议实现类。
                ClientProtocol.class, ClientProtocol.versionID
                ,new InetSocketAddress("127.0.0.1",8787),new Configuration());
        String result = proxy.echo("sam");   // 代理类执行远程调用,并返回值。
        System.out.println(result);
    }
}

4,服务端

import org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.Server;
import java.io.IOException;

public class MyRpcServer {

    public static void main(String[] args) throws HadoopIllegalArgumentException, IOException {
        Server server =new RPC.Builder(new Configuration()).setProtocol(ClientProtocol.class)
                .setInstance(new ClientProtocolImpl()).setBindAddress("127.0.0.1").setPort(8787)
                .setNumHandlers(5).build();  //建立服务器,绑定ip和端口。设置客户端协议接口和实现类
        server.start();
    }
}

5,执行结果如下:

先开启Server, 在开启Client进程,发送请求。 返回echo()方法调用结果。

 

posted @ 2022-06-22 18:49  gaussen126  阅读(98)  评论(0编辑  收藏  举报