Hadoop RPC使用

RPC

RPC(Remote Procedure Call Protocol)远程过程调用协议。一个通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个方法,就像调用本地应用程序中的对象一样。同时将网络的通信细节隐藏起来,使得用户无需额外的关注交互过程,由于RPC大大简化了分布式程序的开发,因此备受欢迎。

RPC通信模型

RPC通常用C/S模式。请求程序是一个客户机,服务提供程序是一个服务器。一个典型的RPC框架如下图所示:
这里写图片描述

  • 通信模块
    两个相互协作的通信模块实现请求 - 应答协议,它们在客户端和服务器之间传递请求和消息,一般不会对数据包进行任何处理。请求-应答协议有同步和异步两种实现,在高并发场景下一般采用异步方式。
  • Stub程序
    客户端和服务器端均包含Stub程序,可将之看作代理程序。它使得远程函数调用表现的跟本地调用一样。对用户完全透明。在客户端它主要将请求信息交给网络模块,此外当服务器发送应答后,解码对应的结果。在服务器端,Stub程序依次编码请求消息中的参数,调用相应的服务过程和编码应答结果的返回值。
  • 调度程序
    接受来自通信模块的请求消息,并根据其中的标识选择一个Stub程序进行处理。
  • 客户程序/服务过程
    请求的发出者和请求的处理者。

hadoop RPC总体架构

Hadoop摒弃了Java原生重量级RPC框架RMI,根据实际场景的需要实现了一个自己的RPC框架。该框架具有如下特点:

  • 透明性
    用户执行RPC调用时跟调用本地方法一样。
  • 高性能
    hadoop需要应对高并发,海量数据的存储与计算,因此RPC的高性能一定是首要的。
  • 跨语言
    “跨语言”这个特性在hadoop最初的版本中支持的不是很好,后面在序列化层支持Protocol Buffers,从理论上来说具备了快语言特性。但是大数据是基于java生态体系构建的,实际的开发中基本不用考虑跨语言需求。但是还是期待在未来的时间里,hadoop生态体系能支持越来越多的语言,让更多的人能参
    与进来。

架构体系
hadoop RPC分为四个部分。

  • 序列化层
    序列化主要作用是将结构化对象转换位字节流便于网络传输或持久化存储,hadoop中支持Protocol Buffers, Apache Avro以及自身实现的Writable序列化方式。
  • 函数调用层
    函数调用层主要定位要调用的函数并执行该函数,hadoop RPC采用了Java反射和动态代理的方式实现。
  • 网络传输层
    hadoop RPC 网络传输采用的是TCP协议。
  • 服务器处理框架层
    服务器端处理框架可抽象为网络IO模型,hadoop RPC中采用了基于Reactor设计模式的事件驱动IO模型,它能保证框架IO处理的高性能。
    这里写图片描述

hadoop RPC使用

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

  1. public static ProtocolProxy getProxy/waitForProxy(…)
    构造一个客户端代理对象(该对象实现了某个协议),用于向服务器发送RPC请求。
  2. public static Server RPC.Builder (Configuration).build()
    为某个协议(实际上是Java接口)实例构造一个服务器对象,用于处理客户端发送的请求。

RPC使用步骤

  1. 定义RPC协议
    RPC协议是客户端和服务器端之间的通信接口,它定义了服务器对外提供的服务接口。新建文件IRPCInterface.java。

    public interface IRPCInterface  extends VersionedProtocol {
        long versionID = 1;    //版本号,默认情况下不同版本号之间的server和client不能通信。
        int add(int a, int b) throws IOException;
    }
  2. 实现RPC协议

    上面实现了协议的“骨架”:接口,现在针对接口进行具体的实现。新建IRPCInterfaceImpl.java文件。

    class IRPCInterfaceImpl implements IRPCInterface {
    
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    
    @Override
    public long getProtocolVersion(String s, long l) throws IOException {
        return IRPCInterface.versionID;
    }
    
    @Override
    public ProtocolSignature getProtocolSignature(String s, long l, int i) throws IOException {
        return new ProtocolSignature(IRPCInterface.versionID,null);
    }
    }
  3. 构造并启动RPC Server
    使用静态类Builder构造一个RPC Server,并调用start()启动server。新建RpcServer.java。

    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.ipc.ProtocolSignature;
    import org.apache.hadoop.ipc.RPC;
    import org.apache.hadoop.ipc.RPC.Server;
    
    public class RpcServer {
        public static void main(String[] args) throws IOException {
            Server server = new RPC.Builder(new Configuration()).
                    setBindAddress("127.0.0.1").setPort(8080).
                    setInstance(new IRPCInterfaceImpl()).
                    setProtocol(IRPCInterface.class).build();
    
            server.start();
        }
    }
    
  4. 构造RPC Client并发送RPC请求
    使用静态方法getProxy构造客户端代理对象,直接通过代理对象调用远程方法。新建RpcClient.java文件。

    扫描二维码关注公众号,回复: 1806685 查看本文章
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import java.io.IOException;
import java.net.InetSocketAddress;

public class RpcClient {
    public static void main(String[] args) throws IOException {
        IRPCInterface proxy = RPC.getProxy(IRPCInterface.class, 1,
                new InetSocketAddress("127.0.0.1", 8080), new Configuration());
        int result = proxy.add(1,2);
        System.out.println("result = " + result);
    }
}

运行

  1. 启动server:运行RpcServer.main方法
  2. 启动client:运行RpcClient .main方法
  3. 运行结果:
    server:
    这里写图片描述
    client:
    这里写图片描述

猜你喜欢

转载自blog.csdn.net/cl2010abc/article/details/80774072