对hadoop之RPC的理解 (3)

  流式接口是HDFS中基于TCP或者HTTP实现的接口,在HDFS中,流式接口包括基于TCP的DataTransferProtocol接口,以及HA架构中Active Namenode和Standby Namenode之间的HTTP接口。

1、DataTransferProtocol

DataTransferProtocol是用来描述写入或者读出Datanode上数据的基于TCP的流式接口,HDFS客户端与数据节点以及数据节点与数据节点之间的数据块的传输就是基于DataTransferProtocol接口实现的。

2、Active Namenode和Standby Namenode间的HTTP接口

  Namenode会定期将文件系统的命名空间保存在一个fsimage文件中,以及会将Namenode的命名空间的修改操作先写入到editlog文件中,定期的合并fsimage和editlog文件。这个合并操作由Secondary Namenode或者Standby Namenode去实现,合并完之后又要同步给Active Namenode,在Active Namenode和Standby Namenode之间的HTTP接口就是用来传输的fsimage文件的。

二、Hadoop RPC的实现

  Hadoop作为一个分布式的存储系统,各个节点之间的通信和交互是必不可少的,所以在hadoop有一套节点之间的通信交互机制。RPC(Pemote Procedure CallProtocol,远程过程调用协议)允许本地程序像调用本地方法一样调用远程机器上的应用程序提供服务,Hadop RPC机制是基于IPC实现的,主要用到了java的动态代理,java NIO以及protobuf等基础技术(没有基于java的RMI)。

  Hadoop RPC框架主要由三个类组成:RPC、Client和Server类,RPC类用于对外提供一个使用Hadoop RPC框架的接口,Client类用于实现客户端功能,Server类用于实现服务端功能。

3.1、RPC类的实现

  客户端调用程序可以通过RPC类提供的waitForProxy()和getProxy()方法获取指定RPC协议的代理对象,然后RPC客户端就可以调用代理对象的方法发送RPC请求到服务器了。
  在服务端,服务端程序调用RPC内部的Builder.build()方法构造一个RPC.Server类,然后调用RPC.server.start()方法启动Server对象监听并响应RPC请求。

3.2、Client类的实现

  HDFS Client会获取一个ClientProtocolPB协议的代理对象,并在这个代理对象上调用RPC方法,代理对象会调用RPC.Client.call()方法将序列化之后的RPC请求发送到服务器。

  Client发送请求与接收响应的流程图如下所示:Client类只有一个入口,即call()方法,代理类会调用Client.call()方法将RPC请求发送到远程服务器,然后等待远程服务器的响应。

对hadoop之RPC的理解

 

 Client发送请求与接收响应的流程图如上所示:主要可以分为如下几个步骤:

Client.call()方法将RPC请求封装成一个Call对象,其中保存了RPC调用的完成标志,返回值信息以及异常信息,然后call()方法会创建一个connection对象,用于管理client和server的socket连接。用ConnectionId作为key,将新建的Connection对象放入到Client.connections字段值保存,以callId作为key,将构造的Call对象放入Connection.calls字段中保存。

Client.call()方法调用Connection.setupIOstreams()方法建立与server的socket连接,setupIOstreams()方法还会启动connection线程,这些线程会监听socket并读取server发回的响应信息。

Client.call()方法调用Connection.sendRpcRequest()方法发送RPC请求到Server。

Client.call()方法调用Call.wait()在Call对象上等待,等待server返回响应信息。

Connection线程收到Server发回的响应信息,根据响应中的信息找到对应的call对象,然后设置Call对象的返回字段,并调用call.notify()唤醒Client.call()方法的线程读取Call对象的返回值。

RPC.Client中发送请求和接收响应的是由两个独立的线程进行的,发送请求线程就是调用Client.call()方法的线程,而接收响应线程则是call()启动的connect线程。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzpff.html