02.HDFS通信协议之ClientProtocol接口

ClientProtocol定义了所有由客户端发起的、由Namenode响应的操作,这个接口非常大,有80多个方法,把这些方法分为如下几类

  1. HDFS文件读相关的操作
  2. HDFS文件写以及追加写的相关操作
  3. 管理HDFS命名空间(namespace)的相关操作
  4. 系统问题与管理相关的操作
  5. 快照相关的操作
  6. 缓存相关的操作
  7. 其他操作

HDFS文件读操作、HDFS文件写与追加写操作、以及命令空间的管理操作,这三个部分都可以在FileSystem类中找到对应的方法,这些方法都是用来支撑Hadoop文件系统实现的

系统问题与管理相关的操作,则是由DFSAdmin这个工具类发起的,其中的方法用于支持管理员配置和管理HDFS的

快照和缓存则都是Hadoop2.X中引入的新特性,ClientProtocol中也有相应的方法用于支持这两个新特性,ClientProtocol中还包括安全、XAttr等方法。

读数据相关方法

ClientPrototol中,与客户端读取文件相关的方法主要有两个,getBlockLocations()和reportBadBlocks()

getBlockLocations()方法定义如下

  public LocatedBlocks getBlockLocations(String src,
                                         long offset,
                                         long length) 
      throws AccessControlException, FileNotFoundException,
      UnresolvedLinkException, IOException;

客户端会调用getBlockLocations()获取HDFS文件指定范围内所有数据块的位置信息,该方法的参数是HDFS文件的文件名以及读取范围,返回值是文件指定范围内所有数据块的文件名以及它们的位置信息,使用LocatedBlocks对象封装。每个数据块的位置信息指的是存储这个数据块副本的所有Datanode的信息,这些Datanode会以与当前客户端的距离远近排序。客户端读取数据时,会首先调用getBlockLocations()方法获取HDFS文件的所有数据块的位置信息,然后客户端会根据这些位置信息从数据节点读取数据块

reportBadBlocks()方法定义如下

public void reportBadBlocks(LocatedBlock[] blocks) throws IOException;

客户端会调用reportBadBlocks()方法向Namenode汇报错误的数据块,当客户端从数据节点读取数据块且发现数据块校验和并不正确时,就会调用这个方法向Namenode汇报这个错误的数据块信息。

追加写数据相关方法

HDFS客户端操作中最重要的一部分就是写入一个新的HDFS文件,或者打开一个已有的HDFS文件并执行追加操作。

ClientPrototol中定义了8个方法支持HDFS文件的写操作,create()、append()、addBlock()、complete()、abandonBlock()、getAddtionnalDatanodes()、updateBlockForPipeline()和updatePipeline()

create()方法定义如下

public HdfsFileStatus create(String src, FsPermission masked,
    String clientName, EnumSetWritable<CreateFlag> flag,
    boolean createParent, short replication, long blockSize, 
    CryptoProtocolVersion[] supportedVersions)
    throws AccessControlException, AlreadyBeingCreatedException,
    DSQuotaExceededException, FileAlreadyExistsException,
    FileNotFoundException, NSQuotaExceededException,
    ParentNotDirectoryException, SafeModeException, UnresolvedLinkException,
    SnapshotAccessControlException, IOException;

create()方法用户在HDFS的文件系统目录树中创建一个新的空文件,创建的路径由src参数指定。这个空文件创建后对于其他的客户端是"可读的",但是这些客户端不能删除、重命名或者移动这个文件,直到这个文件被关闭或者租约过期。客户端写一个新的文件时,会首先调用create()方法在文件系统目录树中创建一个空文件,然后调用addBlock()方法获取存储文件数据的数据块的位置信息,最后客户端就可以根据位置信息建立数据流通道,向数据节点间写入数据了。

append()方法定义如下

public LocatedBlock append(String src, String clientName)
    throws AccessControlException, DSQuotaExceededException,
    FileNotFoundException, SafeModeException, UnresolvedLinkException,
    SnapshotAccessControlException, IOException;

append()方法用于打开一个已有的文件,如果这个文件的最后一个数据块没有写满,则返回这个数据块的位置信息(使用LocatedBlocks对象封装),如果这个文件的最后一个数据块正好写满,则创建一个新的数据块并添加到这个文件中,然后返回这个新添加的数据块的位置信息。客户端追加写一个已有文件时,会先调用append()方法获取最后一个可写数据块的位置信息,然后建立数据流管道,并向数据节点写入追加的数据。如果客户端将这个数据块写满,与create()方法一样,客户端会调用addBlock()方法获取新的数据块

addBlock()方法定义如下

public LocatedBlock addBlock(String src, String clientName,
    ExtendedBlock previous, DatanodeInfo[] excludeNodes, long fileId, 
    String[] favoredNodes)
    throws AccessControlException, FileNotFoundException,
    NotReplicatedYetException, SafeModeException, UnresolvedLinkException,
    IOException;

客户端调用addBlock()方法向指定文件添加一个新的数据块,并获取存储这个数据块副本的所有数据节点的位置信息(使用LocatedBlocks对象封装)。要注意的是,调用addBlock()方法时还要传入上一个数据块的引用。Namenode在分配新的数据块时,会顺便提交上一个数据块,这里previous参数就是上一个数据块的引用。excludeNodes参数则是数据节点的黑名单,保存了客户端无法连接的一些数据节点,建议Namenode在分配保存数据块副本的数据节点时不要考虑这些节点。favoredNodes参数则是客户端所希望保存数据块的数据节点的列表。客户端调用addBlock()方法获取新的数据块的位置信息后,会建立到这些数据节点的数据流管道,并通过数据流管道将数据写入数据节点。

complete()方法定义如下

public boolean complete(String src, String clientName,
                        ExtendedBlock last, long fileId)
    throws AccessControlException, FileNotFoundException, SafeModeException,
    UnresolvedLinkException, IOException;

当客户端完成了整个文件的写入操作后,会调用complete()方法通知Namenode。这个操作会提交新写入HDFS文件的所有数据块,当这些数据块的副本数量满足系统配置的最小副本系数(默认值为1),也就是该文件的所有数据块至少有一个有效副本时,complete()方法会返回true,这是Namenode中文件的状态也会从构建中状态转换为正常状态,否则,complete()会返回false,客户端换就需要重复调用complete()操作,直至该方法返回true。

上面4个方法都是在正常流程时,客户端写文件必须调用的方法。但是对于一个分布式系统来说,写流程中涉及的任何一个节点都有可能出现故障。出现故障的情况也是需要考虑在内的,所以ClientProtocol定义了abandonBlock()、getAddtionnalDatanodes()、updateBlockForPipeline()和updatePipeline()等方法,用于在异常情况下进行恢复操作。

abandonBlock()方法定义如下

public void abandonBlock(ExtendedBlock b, long fileId,
    String src, String holder)
    throws AccessControlException, FileNotFoundException,
    UnresolvedLinkException, IOException;

客户端调用abandonBlock()方法放弃一个新申请的数据块。当客户端获取了一个新申请的数据块,发现无法建立到存储这个数据块副本的某些数据节点的连接时,会调用abandonBlock()方法通知Namenode放弃这个数据块,之后客户端会再次调用addBlock()方法获取新的数据块,并在传入参数时将无法连接的数据节点放入excludeNodes参数列表中,以避免Namenode将数据块的副本分配到该节点上,造成客户端再次无法连接这个节点的情况。

abandonBlock()方法用户处理客户端建立数据流管道时数据节点出现故障的情况。那么如果客户端已经成功建立了数据流管道,在客户端写某个数据块时,存储这个数据块副本的某个数据节点出现了错误如何处理呢?

这个操作就比较复杂了,客户端会先调用getAddtionnalDatanodes()方法向Namenode申请一个新的Datanode来替代出现故障的Datanode。然后客户端会调用updateBlockForPipeline()方法向Namenode申请为这个数据块分配新的时间戳,这样故障节点上的没能写完整的数据块的时间戳就会过期,在后续的块汇报操作中会被删除。最后客户端就可以使用新的时间戳建立新的数据流管道,来执行对数据块的写操作了。数据流管道建立成功后,客户端还需要调用updatePipeline()方法更新Namenode中当前数据块的数据流管道信息。至此,一个完整的恢复操作结束。

上面都是在写数据操作时数据节点发生故障的情况,包括了数据流管道建立时以及建立后数据节点发生故障的情况。在写数据的过程中,Client节点也有可能在任意时刻发生故障,为了防止这种情况,对于任意一个Client打开的文件都需要Client定期调用ClientProtocol.renewLease()方法更新租约。如果Namenode长时间没有收到Client的租约更新消息,就会认为Client发生故障,这时就会触发一个租约恢复操作,关闭文件并且同步所有数据节点上这个文件数据块的状态,确保HDFS系统中这个文件是正确且一致保存的。

当然,在写操作时,Namenode也会发生故障的,这就涉及到HDFS的HA架构了,后面再说。

命名空间管理的相关方法

ClientProtocol中有很重要的一部分操作是对Namenode命名空间的修改。

FileSystem类也定义了对文件系统命名空间修改的API(FileSystem类抽象了一个文件系统对外提供的API接口),HDFS则满足FileSystem类抽象的所有方法,下表总结了FileSystem API与ClientProtocol 接口的对应关系

Hadoop FileSystem 操作ClientProtocol 对应的接口描述
FileSystem.rename()rename()更改文件/目录名称
FileSystem.concat()concat()将两个已有文件拼接成一个
FileSystem.delete()delete()从文件系统中删除指定文件或者目录
FileSystem.mkdirs()mkdirs()一指定名称和权限在文件系统中创建目录
FileSystem.listStatus()getListing()读取一个指定目录下的所有项目
FileSystem.set*()setPermission()
setOwner()
setTimes()
setReplication()
修改文件属性,分别用于修改文件权限、文件主/组、文件修改时间/访问时间以及文件的副本系数
FileSystem.listCorruptFileBlocks()listCorruptFileBlocks()获取文件系统中损坏文件的一部分,如果想要获取文件系统中所有损坏的文件,则循环调用这个方法
FileSystem.getFileStatus()getFileInfo()获取文件/目录的属性
FileSystem.getFileLinkStatus()getFileLinkStatus()获取文件/目录的属性,如果文件指向一个符号链接,则返回这个符号链接的信息
DistributedFileSystem.isFileClosed()isFileClosed()判断指定文件是否关闭了
FileSystem.getContentSummary()getContentSummary()获取文件/目录使用的存储空间信息
FileSystem.createSymlink()createSymlink()对于已经存在的文件创建符号链接
FileSystem.resolveLink()getLinkTarget()获取指定符号链接指向目标

通过上表可以看出ClientProtocol中涉及的命名空间管理的方法都有与之对应的HDFS文件系统API,且方法的名称和参数很相近。如setReplication()

setReplication()在ClientProtocol定义如下

public boolean setReplication(String src, short replication)
    throws AccessControlException, DSQuotaExceededException,
    FileNotFoundException, SafeModeException, UnresolvedLinkException,
    SnapshotAccessControlException, IOException;

setReplication()在FileSystem定义如下

public boolean setReplication(Path src, short replication)
  throws IOException {
  return true;
}

可以看到,setReplication()方法在FileSystem和ClientProtocol中定义的方法名及参数都很接近,大部分情况下,ClientProtocol接口方法定义的参数更多,可以很好地支持FileSystem API定义的操作

系统问题与管理操作

ClientProtocol另一个重要的部分就是支持DFSAdmin工具的接口方法,DFSAdmin是供HDFS管理员管理HDFS集群的命令行工具。一个典型的dfsadmin命令如下

hdfs dfsadmin [参数]

管理员可以添加不同的参数以触发HDFS进行相应的操作

下表给出了ClientProtocol中定义的接口方法与dfsadmin命令参数之间的对应关系。

ClientProtocol接口dfsadmin命令参数
getStatus()用于获取文件系统状态信息,包括磁盘使用情况、复制数据块的数量、损坏数据块的数量、丢失数据块的数量等。对应于dfsadmin命令 '-report'选项
getDatanodeReport()获取集群中存活的、死亡的或者所有的数据节点信息。对应于dfsadmin命令 '-report'选项
getDatanodeStorageReport()获取数据节点上所有存储的信息
setSafeMode()用于进入、离开安全模式,或者获取当前安全模式的状态。对应于dfsadmin命令 '-sagemode’选项
saveNamespace()将Namenode内存中的命令空间保存至新的fsimage中,并且重置editlog。注意,执行这个操作要求必须是处于安全模式中。对应于dfsadmin命令 '-saveNamespace’选项
rollEdits()重置editlog,也就是关闭当前正在写入的editlog文件,开启一个新的editlog文件。注意,执行这个操作要求必须是处于安全模式中。对应于dfsadmin命令 '-rollEdits’选项
restoreFailedStorage()用于当失败的(failed)存储变得可用时,设置是否对这个存储上保存的副本进行恢复操作。对应于dfsadmin命令 '-restoreFailedStorage’选项
refreshNodes()触发Namenode重新读取include/exclude文件。对应于dfsadmin命令 '-refreshNodes’选项
finalizeUpgrade()提交Namenode的升级操作。对应于dfsadmin命令 '-finalizeUpgrade’选项
rollingUpgrade()触发Namenode进行升级操作。对应于dfsadmin命令 '-rollingUpgrade’选项
metaSave()将Namenode中主要的数据结构保存到指定文件中,包括同Namenode心跳过的Datanode、等待复制的数据块、等待删除的数据块、当前正在复制的数据块等信息。对应于dfsadmin命令’-metasave‘选项
setBalancerBandwidth()更改Datanode在进行数据块平衡操作时所占用的带宽。调用这个命令设置的带宽值会覆盖dfs.balance.bandwidthPerSec配置项配置的带宽值。对应于dfsadmin命令’-setBalancerBandwidth‘选项
setQuota()设置目录中的文件/目录的数量配额,以及文件大小配额,对应于dfsadmin命令'-setQuota'、'-clrQuota'、'-setSpaceQuota'和'-clrSpaceQuota'选项,这4个选项的底层都是通过setQuota()触发Namenode操作的

下面看几个重要的方法。

setSafeMode()方法,定义如下

public boolean setSafeMode(HdfsConstants.SafeModeAction action, boolean isChecked) 
    throws IOException;

这里涉及一个安全模式概念。安全模式是Namenode的一种状态,处于该状态的Namenode不接受客户端对命名空间的修改操作,整个命名空间处于只读状态。同时,Namenode也不会向Datanode下发任何数据块的复制、删除指令。管理员可以通过dfsadmin setSafemode命令触发Namenode进入或者退出安全模式,同时还可以使用这个命令查询安全模式的状态。需要注意的是,刚刚启动的Namenode会直接自动进入安全模式,当Namenode中保存的满足最小副本系数的数据块达到一定的比例时,Namenode会自动退出安全模式。而对于用户通过dfsadmin 方式触发Namenode进入安全模式的情况,则只能有管理员手动关闭安全模式,Namenode不可以自动退出。dfsadmin setSafemode命令正是通过调用ClientProtocol.setSafeMode()方法实现的。

了解了安全模式,来看下必须在安全模式中才能进行的两个操作

saveNamespace(),将Namenode内存中的命令空间保存至新的fsimage中,并且重置editlog

rollEdits(),重置editlog,也就是关闭当前正在写入的editlog文件,开启一个新的editlog文件。

refreshNodes()方法会触发Namenode刷新数据节点列表。管理员可以通过include文件指定可以连接到Namenode的数据节点列表,通过exclude文件指定不能连接到Namenode的数据节点列表,当管理员修改了这两个配置文件后,需要通过'-refreshNodes'选项触发Namenode刷新数据节点列表,这个操作会造成Namenode从文件系统中移除已有的数据节点或者添加新的数据节点。

finalizeUpgrade()和rollingUpgrade()操作都是与Namenode升级相关的,管理员可以通过'-rollingUpgrade'选项触发Namenode进行升级操作。当Namenode成功的执行升级操作后,管理员可以通过'-finalizeUpgrade'提交升级操作,提交升级操作会删除升级操作创建的一些临时目录,提交升级操作之后就不可以再回滚了。

快照相关操作

Hadoop 2.X添加了新的快照特性,用户可以为HDFS的任意路径创建快照。快照保存了一个时间点上HDFS某个路径中所有数据的拷贝,快照可以将失效的集群回滚到之前一个正常的时间点上。可以通过"hdfs dfs"命令执行创建、删除以及重命名快照等操作,ClientProtocol也定义了对应的方法来支持快照命令。

在创建快照之前,必须先通过"hdfs dfsadmin -allowSnapshot"命令开启目录快照功能,否则不可以在该目录上创建快照

下表给出了快照操作与ClientProtocol中相关方法的对应关系

方法名作用对应的命令
createSnapshot()创建快照hdfs dfs -createSnapshot <path> [<snapshotName>]
deleteSnapshot()删除快照hdfs dfs -deleteSnapshot <path> <snapshotName>
renameSnapshot()重命名快照hdfs dfs -renameSnapshot <path> <oldName> <newName>
allowSnapshot()开启指定目录的快照功能。一个目录必须在开启快照功能之后才能添加快照hdfs dfsadmin -allowSnapshot <path>
disallowSnapshot()关闭指定目录的快照功能hdfs dfsadmin -disallowSnapshot <path>
getSnapshotDiffReport()获取两个快照间的不同hdfs snapshotDiff <path> <fromSnapshot> <toSnapshot>

缓存相关操作

HDFS 2.3版本添加了集中式缓存管理(HDFS Centralized Cache Management)功能。可以指定一些经常被使用到的数据或者高优先级任务对应的数据,让它们常驻内存而不被淘汰到硬盘上,这对于提升Hadoop系统和上层应用的执行效率与实时性有很大的帮助

这里有两个概念

  1. cache directive,表示要被缓存到内存的文件或者目录
  2. cache pool,用于管理一系列的cache directive,类似于命令空间。同时使用UNIX风格的文件读、写、执行权限管理机制

下表总结了缓存相关命令与ClientProtocol方法之间的对应关系

方法名作用对应的命令
addCacheDirective()添加一个缓存hdfs cacheadmin -addDirective -path <path> -pool <pool-name> [-force] [-replication <replication>] [-ttl <time-to-live>]
modifyCacheDirective()修改缓存hdfs cacheadmin -modifyDirective -id <id> [-path <path>] [-force] [-replication <replication>] [-pool <pool-name>] [-ttl <time-to-live>]
removeCacheDirective()删除缓存hdfs cacheadmin -removeDirective <id>
listCacheDirectives()列出指定路径下的所有缓存hdfs cacheadmin -listDirectives [-stats] [-path <path>] [-pool <pool>]
addCachePool()添加一个缓冲池hdfs cacheadmin -addPool <name> [-owner <owner>] [-group <group>] [-mode <mode>] [-limit <limit>] [-maxTtl <maxTtl>]
modifyCachePool()修改已有缓存池的元数据hdfs cacheadmin -modifyPool <name> [-owner <owner>] [-group <group>] [-mode <mode>] [-limit <limit>] [-maxTtl <maxTtl>]
removeCachePool()删除缓存池hdfs cacheadmin -removePool <name>
listCachePools()列出已有缓存池的信息,包括用户名、用户组、权限等hdfs cacheadmin -listPools [-stats] [<name>]

其他操作

安全相关以及XAttr相关命令,主要都是增加、删除以及List操作。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值