Hadoop RPC详解


  Hadoop中使用RPC的场景很多,比如client和Namenode之间,Namenode和Datanode之间,Namenode和Namenode之间等等。本文只讨论client和Namenode之间的RPC机制,把这一种搞懂了,其它几种也迎刃而解,因为都是同样的道理。Hadoop中的RPC机制可以抽象成4个步骤:

  • 定义RPC协议
  • 实现RPC协议
  • client端获得代理对象
  • server端启动监听

  下面会分别就这4个方面展开讨论。

1 定义RPC协议

  这一步就是定义一个接口,该接口定义了客户端想要调用的服务端的方法,具体到client和Namenode的RPC接口是ClientProtocol,这个接口中的方法不外乎两类,一是操纵命名空间的方法,二是操纵文件流的方法。

2 实现RPC协议

2.1 真实现(服务端)

  服务端必须实现第1步定义的接口中的方法供客户端调用,NameNodeRpcServer类就是服务端对ClientProtocol的具体实现类。

2.2 假实现(客户端)

  假实现是客户端对ClientProtocol的一个实现,相信大家对这里有不少疑问,为何客户端还要实现ClientProtocol,因为正常来说客户端只要将调用什么协议,什么方法,方法参数这三要素传给服务端就够了,完全没有必要去具体实现这个接口。

  之所以客户端要做这看似多余的一步,是因为序列化的问题,我们知道java对象要在网络上传输就必须先序列化,原来接口方法的参数都是未序列化的类型,于是我们在客户端定义了一个接口ClientNamenodeProtocolPB,这个接口除了方法中的参数为序列化类型外与ClientProtocol接口完全一样。接下来我们需要找到一个方法将这两个接口关联起来,于是我们引入了本节的主角ClientNamenodeProtocolTranslatorPB,这个类就是我们所说的假实现了ClientProtocol接口的类,为什么说它是假实现呢,因为它没有真的去实现方法的逻辑,而是在所有方法内部调用ClientNamenodeProtocolPB完成。ClientProtocol、ClientNamenodeProtocolPB和ClientNamenodeProtocolTranslatorPB三者的关系见下图1所示。其实这里用到了适配器模式,ClientNamenodeProtocolTranslatorPB类充当的角色就是一个适配器。
在这里插入图片描述

图1

  可以发现,ClientNamenodeProtocolTranslatorPB内部持有ClientNamenodeProtocolPB对象rpcProxy,ClientNamenodeProtocolTranslatorPB的所有方法都是通过调用rpcProxy的对应方法实现的。以ClientNamenodeProtocolTranslatorPB.rename()方法为例,源码为:

  @Override
  public boolean rename(String src, String dst) throws IOException {
   
    RenameRequestProto req = RenameRequestProto.newBuilder()
        .setSrc(src)
        .setDst(dst).build();

    try {
   
      return rpcProxy.rename(null, req).getResult();
    } catch (ServiceException e) {
   
      throw ProtobufHelper.getRemoteException(e);
    }
  }

3 client端获得代理对象

  下面开始讲解RPC中最难啃的两个部分,请做好战斗准备。

  这段旅程的起点是DFSClient类,这个类是客户端通向Namenode的门面类,是用户使用HDFS各项功能的起点。这个类很庞大,我们这里只讨论和RPC相关的部分。

  这个类定义了namenode字段:

final ClientProtocol namenode;

  在类的构造方法中初始化了该字段:

proxyInfo = NameNodeProxiesClient.createProxyWithClientProtocol(conf,
          nameNodeUri, nnFallbackToSimpleAuth);
this.namenode = proxyInfo.getProxy();

  我们首先看一下NameNodeProxiesClient.createProxyWithClientProtocol()方法,该方法的源码如下:

  public static ProxyAndInfo<ClientProtocol> createProxyWithClientProtocol(
      Configuration conf, URI nameNodeUri, AtomicBoolean fallbackToSimpleAuth)
      throws IOException {
   
    AbstractNNFailoverProxyProvider<ClientProtocol> failoverProxyProvider =
        createFailoverProxyProvider(conf, nameNodeUri, ClientProtocol.class,
            true, fallbackToSimpleAuth);

    if (failoverProxyProvider == null) {
   
      // NonHA  
      InetSocketAddress nnAddr = DFSUtilClient.getNNAddress(nameNodeUri);
      Text dtService = SecurityUtil.buildTokenService(nnAddr);
      ClientProtocol proxy = createNonHAProxyWithClientProtocol(nnAddr, conf,
          UserGroupInformation.getCurrentUser(), true, fallbackToSimpleAuth);
      return new ProxyAndInfo<>(proxy, dtService, nnAddr);
    } else {
   
      // HA
      return createHAProxy(conf, nameNodeUri, ClientProtocol.class,
          failoverProxyProvider);
    }
  }

  可以发现proxyInfo的实际类型是ProxyAndInfo,ProxyAndInfo封装了ClientProtocol对象proxy和它对应的service ID,proxyInfo.getProxy()方法就是获得里面封装的ClientProtocol对象。因此我们重点关注proxy的初始化过程。

  根据集群是否是HA,proxy对应着两种初始化方法。我们先来看NonHA的情况。

3.1 NonHA proxy

  在这种情况下,会调用createNonHAProxyWithClientProtocol()方法,该方法的源码如下:

  public static ClientProtocol createNonHAProxyWithClientProtocol(
      InetSocketAddress address, Configuration conf, UserGroupInformation ugi,
      boolean withRetries, AtomicBoolean fallbackToSimpleAuth
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值