转自:http://huashuizhuhui.iteye.com/blog/1876145
Hadoop中节点之间的通信是比较复杂的一个网络,若可以把它们之间的通信网络了解清楚,那么对于Hadoop的整体框架理解会有很大帮助。
HDFS中有5种协议:
DatanodeProtocol ( DataNode && NameNode)
InterDatanodeProtocol ( DataNode && DataNode)
ClientDatanodeProtocol (Client && DataNode)
ClientProtocol (Client && NameNode)
NamenodeProtocol ( Secondry NameNode && NameNode)
这5种协议在几个部分通讯时的应用如下图所示:
下面是协议接口的继承层次关系,并作简单介绍:
- org.apache.hadoop.ipc.VersionedProtocol
- org.apache.hadoop.hdfs.protocol.ClientProtocol
- org.apache.hadoop.hdfs.protocol.ClientDatanodeProtocol
- org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol
- org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol
- org.apache.hadoop.hdfs.server.protocol.InterDatanodeProtocol
所有的HDFS通讯协议都是建立在TCP/IP协议之上,客户端通过一个可配置的TCP端口连接到Namenode,通过ClientProtocol协 议与Namenode交互。而Datenode使用的是DatenodeProtocol协议与Namenode交互。一个远程调用(RPC)模型被抽象 出来封装ClientPortocol和Datenode协议。在设计上,Namenode不会主动发起RPC,而是响应来自客户端或者Datanode 的RPC请求。
(1)VersionedProtocol
Superclass of all protocols that use Hadoop RPC.协议是Hadoop RPC的最顶层协议接口的抽象。
(2)ClientProtocol
ClientProtocol是hdfs客户端与NameNode通信的信息接口,接口定义了所有的操作,比如打开或者关闭文件等等。当客户端进程想要与Namenode进程进行通信的时候,需要通过org.apache.hadoop.hdfs.DistributedFileSystem类,基于ClientProtocol协议来实现交互过程。用户代码通过ClientProtocol协议,可以操纵HDFS的目录命名空间、打开与关闭文件流等。 ClientProtocol提供给客户端,用于访问NameNode。它包含了文件角度上的HDFS功能。一般来说,程序员通过org.apache.hadoop.fs.FileSystem来和HDFS打交道,不需要直接使用该接口。
主要方法说明:
- 1)LocatedBlocks getBlockLocations(String src,long offset,long length)
- @param src 文件名称
- @param offset 范围的起始偏移位置
- @param length 范围大小,即offset+length
- 获取到指定范围内,指定文件的所有块的位置信息。调用该方法返回的LocatedBlocks对象包含的内容为:文件长度、组成文件的块及其存储位置(所在的Datanode数据结点)。对于每个块所在DataNode结点的位置,是基于“到文件系统客户端地址的距离最近”的原则进行了排序。文件系统客户端必须与制定的Datanode进行交互,才能获取到所需要的实际的块据块。这是个比较重要的函数,当Client读取hdfs的文件,会先去NameNode上取得该文件的Block信息,然后根据Block的位置信息在去DataNode上读Block的数据。
- 2)void create(String src,FsPermission masked,String clientName, boolean overwrite, boolean createParent, short replication,long blockSize)
- @param src 被创建文件的路径
- @param masked 权限
- @param clientName 当前客户端名称
- @param overwrite 如果待创建的文件已经存在,指定是否重写该文件
- @param replication 块副本因子
- @param blockSize 块的最大长度
- 在命名空间中创建一个文件入口。该方法将创建一个由src路径指定的空文件,该路径src应该反映了从root目录开始的一个完整路径名称。从客户端的角度,Namenode并没有“当前”目录的概念。一旦文件创建成功,该文件就是可见的,并可以被其它客户端来执行读操作。但是,其它客户端不能够对该文件进行删除、重命名、重写,而这些操作只有在该文件被完全或明确指定为租约到期,才可以执行。每个块都具有最大长度限制,如果客户端想要创建多个块,可以调用addBlock(String, String)方法来实现。
- 3) public LocatedBlock append(String src, String clientName)
- 该函数实现对现有文件的追加操作,src执行追加的文件路径,而clientName指定当前的Client名,向文件src中追加写入内容,返回一个LocatedBlock对象,该对象封装了Block(Hadoop基本文件块)和DatanodeInfo[](Datanode的状态信息),通过追加写操作后的返回信息,可以定位到追加写入最后部分块的信息。只有当hdfs开启了dfs.support.append之后才可以进行文件的追加操作。返回值是该问的最后一个Block块信息,追加操作是发生在最后一个Block的,并不是创建新的Block。也就是说,对于hdfs上的文件来说,最多会有一个小于BlockSize的块。
- 4) boolean recoverLease(String src, String clientName) throws IOException;
- 5) boolean setReplication(String src, short replication) throws IOException
- @param src file name 文件名称
- @param replication new replication新的副本因子
- 该方法为一个指定的文件修改块副本因子。Namenode会为指定文件设置副本因子,但是,不期望在调用该方法的过程修改实际块的副本因子,而是由后台块维护进程来执行:如果当前副本因子小于设置的新副本因子,需要增加一些块副本,如果当前副本因子大于设置的新副本因子,就会删除一些块副本。实际的Block个数的修改并不是同步发生的,是由NameNode后台的检查进程来实现的。
- 当后台进行发现当前文件的执行副本个数跟实际副本个数不相同的情况下,会在向DataNode发送的消息中包含增加Block或者删除Block的请求。
- 6) boolean complete(String src, String clientName) throws IOException
- 客户端完成对指定文件的写操作,并期望能够写完,在写完以后关闭文件释放租约。对src指定文件的写入操作完毕后调用该函数来完成操作。返回值为true表示该文件已经被成功的关闭了,否则就需要再次调用该函数查看状态。只有该文件的所有的Block全部成功的写入了最少的复制数才会返回成功。
- 7) void reportBadBlocks(LocatedBlock[] blocks) throws IOException
- 客户端向Namenode报告corrupted块的信息(块在Datanode上的位置信息)
- 8) 重命名、删除、创建目录等
- public boolean rename(String src, String dst)
- public boolean delete(String src)
- public boolean mkdirs(String src, FsPermission masked)
- 9) void renewLease(String clientName) throws IOException
- 租约是客户端对文件写操作时需要获叏的一个凭证。客户端的租约管理径简单,包括了增加的 put 和初除的 remove 方法,run 方法会定期执行,并通过 ClientProtocl 的 renewLease,自劢延长租约
- 10)DatanodeInfo[] getDatanodeReport(FSConstants.DatanodeReportType type)
- 获取集群系统中当前的Datanode的状态报告,每个Datanode返回一个DatanodeInfo对象,包括Datanode的类型LIVE、DEAD或ALL.
- 11) boolean setSafeMode(FSConstants.SafeModeAction action)
- 通过调用该方法可以执行如下操作:进入安全模式、退出安全模式、获取安全模式。当一个Namenode启动时候,首先会进入到安全模式这种特殊状态,在该状态下不能够进行数据块的复制操作。Namenode接收HDFS集群中所有的Datanode结点的心跳状态报告和数据块状态报告,根据状态报告来决定是否开始进入工作状态。如果某些Datanode结点发送的心跳状态报告不正常或者根本无从接收到,Namenode会将这些Datanode视为故障结点,在进入工作状态的时候,将这些故障结点排除在工作集群之外。如果某些Datanode结点上的数据块状态报告存在问题,会根据要求进行处理,比如某Datanode据结点上数据块的块副本未达到副本因子,则会在退出安全模式之后,进行块复制操作,满足副本要求。
- 12) void refreshNodes() throws IOException
- 告诉Namenode重新读取集群结点列表。NameNode 上有个 DataNode 在线列表和 DataNode 离线列表吗,返个命令可以让 NameNode 从 新读返两个文件。
- 13) void finalizeUpgrade() throws IOException
- 完成之前的升级操作,删除在升级期间保存的文件系统的状态,一旦执行该方法,改变将不可逆转。
(3) ClientDatanodeProtocol
ClientDatanodeProtocol协议是客户端进程与Datanode进程之间进行通信所使用的协议;
主要方法说明:
- 1)LocatedBlock recoverBlock(Block block,boolean keepLength,DatanodeInfo[] targets)
- @param block 指定的数据块
- @param keepLength 保持数据块的长度
- @param targets 指定的块的可能位置列表
- @return 如果恢复成功,返回块ID和时间戳
- 2) Block getBlockInfo(Block block) throws IOException;
- 3)BlockLocalPathInfo getBlockLocalPathInfo(Block block,Token<BlockTokenIdentifier> token) throws IOException;
(4) DatanodeProtocol
DatanodeProtocol协议是当Datanode进程需要与NameNode进程进行通信是需要基于此协议,例如发送心跳报告和块状态报告;一般来说Namenode不直接对Datanode进行RPC调用,如果一个Namenode需要与Datanode通信,唯一的方式就通过调用该协议接口定义的方法。
- 当接收到Datanode的命令的时候,根据下述状态码确定Datanode应该执行何种操作
- final static int DNA_UNKNOWN = 0;
- // unknown action
- final static int DNA_TRANSFER = 1;
- // transfer blocks to another datanode
- // 将数据块从一个Datanode转移到另一个Datanode
- final static int DNA_INVALIDATE = 2;
- // invalidate blocks// 未验证数据块
- final static int DNA_SHUTDOWN = 3;
- // shutdown node// 关闭Datanode
- final static int DNA_REGISTER = 4;
- // re-register // 重新注册
- final static int DNA_FINALIZE = 5;
- // finalize previous upgrade// 完成先前执行的升级操作
- final static int DNA_RECOVERBLOCK = 6;
- // request a block recovery// 数据块恢复操作请求
- final static int DNA_ACCESSKEYUPDATE = 7;
- // update access key
- final static int DNA_BALANCERBANDWIDTHUPDATE = 8;
- // update balancer bandwidth
主要方法:
- 1) DatanodeRegistration register(DatanodeRegistration registration)
- s启动的时候,向NameNode注册该DataNode。registration表示DataNode的注册信息,主要包含DataNode的机器名,DataNode的端口,storageID,infoserver的端口,ipc server的端口,StorageInfo等
- 2) DatanodeCommand[] sendHeartbeat(DatanodeRegistration registration,
- long capacity,
- long dfsUsed, long remaining,
- int xmitsInProgress,
- int xceiverCount) throws IOException;
- 工作过程中,定期向NameNode发送的心跳信息,告诉NameNode自己还是活着的,在发送心跳的过程中也会顺便发送一些DataNode的状态信息。比如:当前DataNode的存储能力。已经空间,剩余空间等等。发送心跳的频率由dfs.heartbeat.interval参数控制,默认是3秒。NameNode接受到DataNode的心跳信息后,会将一些关于该DataNode的命令信息返回给DataNode,通过DatanodeCommand[]结构。
- 3) DatanodeCommand blockReport(DatanodeRegistration registration,long[] blocks)
- 在DataNode启动后会通过该方法向NameNode报告所有的本地存储的BLOCK的信息。块信息存储在long数组blocks中,使用long代替Block类型是为了节省内存使用
- 4) void blocksBeingWrittenReport(DatanodeRegistration registration,
- ong[] blocks) throws IOException;
- 5) void blockReceived(DatanodeRegistration registration,
- Block blocks[],
- String[] delHints) throws IOException;
- ataNode向NameNode报告最近接收到的Block信息。比如当该DataNode产生新的Block,或者其他的DataNode复制一个Block到该DataNode,DataNode就会调用该方法向NameNode报告。
- 6) public NamespaceInfo versionRequest() throws IOException;
- ode获取NamespaceInfo信息,NamespaceInfo主要包含buildVersion和distributedUpgradeVersion信息。
(5)NamenodeProtocol
该协议接口定义了次级Namenode(Secondary NameNode)与Namenode进行通信所需进行的操作。其中,Secondary NameNode是一个用来辅助Namenode的服务器端进程,主要是对映像文件执行特定的操作,另外还包括获取指定Datanode上块的操作。
- 1) BlocksWithLocations getBlocks(DatanodeInfo datanode, long size)
- anode指定的DataNode上,块大小为size的Block信息。
- 2) long getEditLogSize() throws IOException;
- 使用中的edit log的大小,以字节为单位
- 3) CheckpointSignature rollEditLog() throws IOException;
- ditLog文件,并重新打开一个新的,当系统处于安全模式下,执行该方法会失败
- 4) void rollFsImage() throws IOException;
- 回滚FsImage日志:删除旧的FsImage,拷贝新的映像到FsImage文件中,删除旧的EditLog文件并重命名edits.new为edits。
(6)InterDatanodeProtocol
InterDatanodeProtocol协议是Datanode进程之间进行通信的协议,例如客户端进程启动复制数据块,此时可能需要在Datanode结点之间进行块副本的流水线复制操作。
- 1) BlockRecoveryInfo startBlockRecovery(Block block) ;
- 为Recovery Block 做准备工作
- 2) void updateBlock(Block oldblock, Block newblock, boolean finalize);
- 更新数据块