一、概述

RPC 协议是使用 Hadoop RPC 框架的第一步,HDFS 为各个节点之间抽象了不同的 RPC 协议,例如 ClientProtocol 抽象了客户端与名字节点之间的通信协议,HDFS 客户端调用 ClientProtocol.rename() 方法,Namenode 服务器就会更改指定 HDFS 文件的文件名。而 DatanodeProtocol 则抽象了数据节点与名字节点之间的通信协议。

protocol

1.1. 协议栈

对于 HDFS 中的所有 RPC 协议,都会存在一个如图所示的协议栈:

RPC

对于 ClientProtocol,存在对应的支持序列化的接口 ClientNamenodeProtocolPB,同时还存在 ClientNamenodeProtocolTranslatorPB 以及 ClientNamenodeProtocolServerSideTranslatorPB 两个类用于进行协议适配

二、实现

2.1. ClientProtocol 协议

ClientProtocol 协议定义了 HDFS 客户端与 Namenode 交互的所有接口方法(例如 rename()、mkdir()等)

2.1.1. 结构

  1. ClientNamenodeProtocolTranslatorPB 这个类是 RPC 客户端侧最重要的类之一,将客户端的请求参数封装成可以序列化的 protobuf 格式,然后通过代理类(实现了 ClientNamenodeProtocolPB 接口的代理类)发送出去。
  2. NameNodeRpcServerNamenode 侧响应 ClientProtocol 调用的类,它会执行 HDFS 操作并将操作结果返回。

2.2. ClientNamenodeProtocolPB 协议

ClientProtocol 是 HDFS 客户端与名字节点之间的接口,但是在 RPC 调用中,RPC 方法的参数和返回值都必须是可序列化的,HDFS 定义了一个新的 ClientNamenodeProtocolPB 协议对 ClientProtocol 协议中方法的参数和返回值进行包装。

ClientNamenodeProtocolPB 协议定义的方法与 ClientProtocol 一样,但是参数和返回值使用 protobuf 序列化后的格式,这样ClientNamenodeProtocolPB 请求就可以通过网络传输。

Hadoop RPC 使用了 protobuf 工具,定义 ClientNamenodeProtocol.proto 文件,将 ClientProtocol 的参数抽象为一个 *RequestProto 对象,而将返回值抽象为一个 *ResponseProto 对象。

以 rename() 方法为例,ClientNamenodeProtocol.rename()方法的参数是 RenameRequestProto,返回值是 RenameResponseProto。RenameRequestProto 和 RenameResponseProto 是 protobuf 定义的用于封装客户端请求参数以及服务端返回值的类,其结构也是在ClientNamenodeProtocol.proto 文件中定义。

2.3. 适配器类

ClientNamenodeProtocolTranslatorPB 类是 RPC Client 侧的适配器类,ClientNamenodeProtocolServerSideTranslatorPB 则是 RPC Server 侧的适配器类。

2.3.1. 客户端

Client 侧的适配器用于将 ClientProtocol 的请求转换为 ClientNamenodeProtocolPB 请求。

DFSClient 持有一个 ClientNamenodeProtocolTranslatorPB 类的引用,用于将 ClientProtocol 协议上的请求适配成 ClientNamenodeProtocolPB 协议的请求。ClientNamenodeProtocolTranslatorPB 将 ClientProtocol 请求的参数序列化,调用 rpcProxy 对象(实现了 ClientNamenodeProtocolPB 接口)上的对应方法,完成适配操作。

以 rename()方法调用作为例子,ClientNamenodeProtocolTranslatorPB 执行了两个操作来完成 ClientProtocol.rename()调用的适配功能。

2.3.2. 服务端

Server 侧的适配器则是将 ClientNamenodeProtocolPB 请求转换为 ClientProtocol 请求。

ClientNamenodeProtocolServerSideTranslatorPB 将 ClientNamenodeProtocolPB 请求的参数反序列化,然后在 ClientProtocol 服务对象 server 上调用对应的方法即可完成适配工作。

以 rename() 方法为例,ClientNamenodeProtocolServerSideTranslatorPB.rename()会首先反序列化请求参数 RenameRequestProto 对象,然后调用 server 对象的 rename() 方法执行重命名操作,最后将返回值序列化为 RenameResponseProto 对象并返回。